diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp index 318d071..f1362aa 100644 --- a/src/render/software/CanvasPixelShader.cpp +++ b/src/render/software/CanvasPixelShader.cpp @@ -31,6 +31,11 @@ int CanvasPixelShader::processParallelUnit(int unit) { for (int y = 0; y < limit_y; y += sub_chunk_size) { + if (interrupted) + { + return 0; + } + if (sub_chunk_size == chunk_size or x % prev_sub_chunk_size != 0 or y % prev_sub_chunk_size != 0) { // Resolve the pixel color diff --git a/src/render/software/CanvasPixelShader.h b/src/render/software/CanvasPixelShader.h index ce321c1..c5fe190 100644 --- a/src/render/software/CanvasPixelShader.h +++ b/src/render/software/CanvasPixelShader.h @@ -20,7 +20,7 @@ class CanvasPixelShader: public ParallelWorker public: CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y); - virtual int processParallelUnit(int unit); + virtual int processParallelUnit(int unit) override; private: const SoftwareCanvasRenderer &renderer; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index af9c6ff..a4e6067 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -35,6 +35,8 @@ Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id, const Color &c renderer(renderer), client_id(client_id) { this->color = new Color(color); + + interrupted = false; } Rasterizer::~Rasterizer() @@ -42,6 +44,11 @@ Rasterizer::~Rasterizer() delete color; } +void Rasterizer::interrupt() +{ + interrupted = true; +} + void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3) { ScanPoint point1, point2, point3; diff --git a/src/render/software/Rasterizer.h b/src/render/software/Rasterizer.h index e364df6..a4157e8 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -22,6 +22,7 @@ public: virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0; virtual Color shadeFragment(const CanvasFragment &fragment) const = 0; + virtual void interrupt(); protected: void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3); @@ -34,6 +35,7 @@ protected: Color* color; SoftwareRenderer *renderer; int client_id; + bool interrupted; private: void scanGetDiff(ScanPoint *v1, ScanPoint *v2, ScanPoint *result); diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index 89436b9..39b09ab 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -13,8 +13,8 @@ class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer public: SkyRasterizer(SoftwareRenderer* renderer, int client_id); - virtual void rasterizeToCanvas(CanvasPortion* canvas); - virtual Color shadeFragment(const CanvasFragment &fragment) const; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 41890c5..9fdda8f 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -19,6 +19,8 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer() rasterizers.push_back(new SkyRasterizer(this, 0)); rasterizers.push_back(new WaterRasterizer(this, 1)); rasterizers.push_back(new TerrainRasterizer(this, 2)); + + current_work = NULL; } SoftwareCanvasRenderer::~SoftwareCanvasRenderer() @@ -59,14 +61,33 @@ void SoftwareCanvasRenderer::render() for (int x = 0; x < nx; x++) { CanvasPortion *portion = canvas->at(x, y); - portion->preparePixels(); - rasterize(portion, true); - postProcess(portion, true); + + if (not render_interrupt) + { + portion->preparePixels(); + rasterize(portion, true); + } + + if (not render_interrupt) + { + applyPixelShader(portion, true); + } + portion->discardPixels(); } } } +void SoftwareCanvasRenderer::interrupt() +{ + SoftwareRenderer::interrupt(); + + if (current_work) + { + current_work->interrupt(); + } +} + const std::vector &SoftwareCanvasRenderer::getRasterizers() const { return rasterizers; @@ -85,7 +106,7 @@ void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) } } -void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) +void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threaded) { // Subdivide in chunks int chunk_size = 64; @@ -96,8 +117,16 @@ void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded) // Render chunks in parallel for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) { + if (render_interrupt) + { + break; + } + CanvasPixelShader shader(*this, portion, chunk_size, sub_chunk_size, chunks_x, chunks_y); ParallelWork work(&shader, units); + + current_work = &work; work.perform(); + current_work = NULL; } } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index e18f150..93cf0cb 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -36,6 +36,8 @@ public: */ void render(); + virtual void interrupt() override; + /** * @brief Get the list of objects that can be rasterized to polygons on a canvas. */ @@ -52,19 +54,21 @@ protected: * * If 'threaded' is true, the rasterization will take advantage of multiple CPU cores. */ - void rasterize(CanvasPortion* portion, bool threaded); + void rasterize(CanvasPortion *portion, bool threaded=false); /** - * @brief Apply post-processing to fragments stored in the CanvasPortion. + * @brief Apply pixel shader to fragments stored in the CanvasPortion. * - * If 'threaded' is true, the post-processing will take advantage of multiple CPU cores. + * If 'threaded' is true, the shader will take advantage of multiple CPU cores. */ - void postProcess(CanvasPortion* portion, bool threaded=true); + void applyPixelShader(CanvasPortion *portion, bool threaded=true); private: - Canvas* canvas; + Canvas *canvas; std::vector rasterizers; bool started; + + ParallelWork *current_work; }; } diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 04f8ded..cb6b278 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -67,7 +67,7 @@ public: void disableAtmosphere(); void disableAtmosphere(const std::vector &lights); - void interrupt(); + virtual void interrupt(); inline Scenery* getScenery() const {return scenery;} diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index ac0afdf..c0713a4 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -226,10 +226,6 @@ int TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chu return !renderer->render_interrupt; } -void TerrainRasterizer::rasterize() -{ -} - void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { queue = new ParallelQueue(); diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 0e6537f..0ae3d7b 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -43,15 +43,8 @@ public: void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height); - /** - * Start the final rasterization of terrain. - * - * This will push the rasterized quads in the render area, waiting for post process. - */ - virtual void rasterize(); - - virtual void rasterizeToCanvas(CanvasPortion* canvas); - virtual Color shadeFragment(const CanvasFragment &fragment) const; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; private: ParallelQueue* queue; diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 902d179..4d587ae 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -15,8 +15,8 @@ public: void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size); - virtual void rasterizeToCanvas(CanvasPortion* canvas); - virtual Color shadeFragment(const CanvasFragment &fragment) const; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; }; } diff --git a/src/system/ParallelWork.cpp b/src/system/ParallelWork.cpp index c77aca3..24a6096 100644 --- a/src/system/ParallelWork.cpp +++ b/src/system/ParallelWork.cpp @@ -172,6 +172,11 @@ int ParallelWork::perform(int thread_count) return done; } +void ParallelWork::interrupt() +{ + worker->interrupt(); +} + void ParallelWork::returnThread(ParallelWork::ParallelThread *thread) { mutex->acquire(); diff --git a/src/system/ParallelWork.h b/src/system/ParallelWork.h index 3e6d923..f1b6133 100644 --- a/src/system/ParallelWork.h +++ b/src/system/ParallelWork.h @@ -48,6 +48,13 @@ public: */ int perform(int thread_count=-1); + /** + * Tell the threads to interrupt what they are doing. + * + * This will also call interrupt() on the worker. + */ + void interrupt(); + private: void returnThread(ParallelThread *thread); diff --git a/src/system/ParallelWorker.cpp b/src/system/ParallelWorker.cpp index 0e64c57..d08dc7b 100644 --- a/src/system/ParallelWorker.cpp +++ b/src/system/ParallelWorker.cpp @@ -2,8 +2,14 @@ ParallelWorker::ParallelWorker() { + interrupted = false; } ParallelWorker::~ParallelWorker() { } + +void ParallelWorker::interrupt() +{ + interrupted = true; +} diff --git a/src/system/ParallelWorker.h b/src/system/ParallelWorker.h index b77f08c..2b90518 100644 --- a/src/system/ParallelWorker.h +++ b/src/system/ParallelWorker.h @@ -21,6 +21,14 @@ public: * This method will be called from any thread in the thread pool used by the ParallelWork. */ virtual int processParallelUnit(int unit) = 0; + + /** + * Method to reimplement to know when to interrupt the processing of units. + */ + virtual void interrupt(); + +protected: + bool interrupted; }; }