From 7c7b6043c56046ff0a248f9d8e282b1587e9ee11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 23 Aug 2015 20:22:37 +0200 Subject: [PATCH] Improved render progress. A bug was also fixed where some canvas pixels were shaded twice, leading to a performance loss. --- src/render/software/CanvasPixelShader.cpp | 12 ++- src/render/software/CanvasPixelShader.h | 3 +- src/render/software/Rasterizer.cpp | 17 +---- src/render/software/Rasterizer.h | 19 +++-- src/render/software/RenderProgress.cpp | 54 +++++++++++++ src/render/software/RenderProgress.h | 43 +++++++++++ src/render/software/SkyRasterizer.cpp | 17 +++-- src/render/software/SkyRasterizer.h | 7 +- .../software/SoftwareCanvasRenderer.cpp | 48 +++++++----- src/render/software/SoftwareCanvasRenderer.h | 9 ++- src/render/software/TerrainRasterizer.cpp | 75 +++++++++++++------ src/render/software/TerrainRasterizer.h | 20 +++-- src/render/software/WaterRasterizer.cpp | 48 ++++++++---- src/render/software/WaterRasterizer.h | 6 +- src/render/software/software.pro | 6 +- src/render/software/software_global.h | 1 + src/tests/RenderProgress_Test.cpp | 33 ++++++++ src/tests/tests.pro | 3 +- 18 files changed, 320 insertions(+), 101 deletions(-) create mode 100644 src/render/software/RenderProgress.cpp create mode 100644 src/render/software/RenderProgress.h create mode 100644 src/tests/RenderProgress_Test.cpp diff --git a/src/render/software/CanvasPixelShader.cpp b/src/render/software/CanvasPixelShader.cpp index ee8b9a9..80468af 100644 --- a/src/render/software/CanvasPixelShader.cpp +++ b/src/render/software/CanvasPixelShader.cpp @@ -6,16 +6,18 @@ #include "CanvasPixel.h" #include "CanvasFragment.h" #include "Rasterizer.h" +#include "RenderProgress.h" -CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y): - renderer(renderer), portion(portion), chunk_size(chunk_size), sub_chunk_size(sub_chunk_size), chunks_x(chunks_x), chunks_y(chunks_y) + +CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, RenderProgress *progress, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y): + renderer(renderer), portion(portion), progress(progress), chunk_size(chunk_size), sub_chunk_size(sub_chunk_size), chunks_x(chunks_x), chunks_y(chunks_y) { } void CanvasPixelShader::processParallelUnit(int unit) { // Locate the chunk we work on - int prev_sub_chunk_size = chunk_size * 2; + int prev_sub_chunk_size = sub_chunk_size * 2; int chunk_x = unit / chunks_y; int chunk_y = unit % chunks_y; int base_x = chunk_x * chunk_size; @@ -29,6 +31,7 @@ void CanvasPixelShader::processParallelUnit(int unit) // Iterate on sub-chunks for (int x = 0; x < limit_x; x += sub_chunk_size) { + int done = 0; for (int y = 0; y < limit_y; y += sub_chunk_size) { if (interrupted) @@ -57,7 +60,10 @@ void CanvasPixelShader::processParallelUnit(int unit) portion->setColor(base_x + x + fx, base_y + y + fy, composite); } } + + done++; } } + progress->add(done); } } diff --git a/src/render/software/CanvasPixelShader.h b/src/render/software/CanvasPixelShader.h index 76a6c75..4fd10e0 100644 --- a/src/render/software/CanvasPixelShader.h +++ b/src/render/software/CanvasPixelShader.h @@ -18,13 +18,14 @@ namespace software { class CanvasPixelShader: public ParallelWorker { public: - CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y); + CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, RenderProgress *progress, int chunk_size, int sub_chunk_size, int chunks_x, int chunks_y); virtual void processParallelUnit(int unit) override; private: const SoftwareCanvasRenderer &renderer; CanvasPortion *portion; + RenderProgress *progress; int chunk_size; int sub_chunk_size; int chunks_x; diff --git a/src/render/software/Rasterizer.cpp b/src/render/software/Rasterizer.cpp index ed8ff8f..227782c 100644 --- a/src/render/software/Rasterizer.cpp +++ b/src/render/software/Rasterizer.cpp @@ -5,6 +5,7 @@ #include "CanvasPortion.h" #include "CanvasFragment.h" #include "Vector3.h" +#include "RenderProgress.h" struct paysages::software::ScanPoint { @@ -31,14 +32,12 @@ struct paysages::software::RenderScanlines int right; }; -Rasterizer::Rasterizer(SoftwareRenderer* renderer, int client_id, const Color &color): - renderer(renderer), client_id(client_id) +Rasterizer::Rasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id, const Color &color): + renderer(renderer), progress(progress), client_id(client_id) { this->color = new Color(color); interrupted = false; - predicted_poly_count = 0; - done_poly_count = 0; } Rasterizer::~Rasterizer() @@ -51,16 +50,6 @@ void Rasterizer::interrupt() interrupted = true; } -void Rasterizer::addPredictedPolys(int count) -{ - predicted_poly_count += count; -} - -void Rasterizer::addDonePolys(int count) -{ - done_poly_count += count; -} - 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 b633bc2..53662d4 100644 --- a/src/render/software/Rasterizer.h +++ b/src/render/software/Rasterizer.h @@ -15,19 +15,24 @@ typedef struct RenderScanlines RenderScanlines; class SOFTWARESHARED_EXPORT Rasterizer { public: - Rasterizer(SoftwareRenderer *renderer, int client_id, const Color &color); + Rasterizer(SoftwareRenderer *renderer, RenderProgress *progress, int client_id, const Color &color); virtual ~Rasterizer(); inline SoftwareRenderer *getRenderer() const {return renderer;} - virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0; virtual Color shadeFragment(const CanvasFragment &fragment) const = 0; virtual void interrupt(); -protected: - void addPredictedPolys(int count=1); - void addDonePolys(int count=1); + /** + * Abstract method to prepare for the rasterization process, and return the estimated progress count. + */ + virtual int prepareRasterization() = 0; + /** + * Abstract method to effectively do the rasterization on a canvas. + */ + virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0; +protected: void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3); void pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3); @@ -37,6 +42,7 @@ protected: Color* color; SoftwareRenderer *renderer; + RenderProgress *progress; int client_id; bool interrupted; @@ -46,9 +52,6 @@ private: void pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point); void pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1, ScanPoint *point2); void renderScanLines(CanvasPortion *canvas, RenderScanlines *scanlines); - - int predicted_poly_count; - int done_poly_count; }; } diff --git a/src/render/software/RenderProgress.cpp b/src/render/software/RenderProgress.cpp new file mode 100644 index 0000000..73e989a --- /dev/null +++ b/src/render/software/RenderProgress.cpp @@ -0,0 +1,54 @@ +#include "RenderProgress.h" + +#include "Mutex.h" + +RenderProgress::RenderProgress(int count) +{ + lock = new Mutex(); + global = 0.0; + step = 1.0 / (double)count; +} + +paysages::software::RenderProgress::~RenderProgress() +{ + delete lock; +} + +void RenderProgress::add(int value) +{ + lock->acquire(); + + global += step * (double)value; + + lock->release(); +} + +void RenderProgress::enterSub(int count) +{ + struct RenderSub sub; + sub.start = global; + sub.end = global + step; + sub.count = count; + sub.previous_step = step; + + lock->acquire(); + + subs.push(sub); + step /= (double)count; + + lock->release(); +} + +void RenderProgress::exitSub() +{ + lock->acquire(); + + struct RenderSub sub = subs.top(); + + global = sub.end; + step = sub.previous_step; + + subs.pop(); + + lock->release(); +} diff --git a/src/render/software/RenderProgress.h b/src/render/software/RenderProgress.h new file mode 100644 index 0000000..0f58518 --- /dev/null +++ b/src/render/software/RenderProgress.h @@ -0,0 +1,43 @@ +#ifndef RENDERPROGRESS_H +#define RENDERPROGRESS_H + +#include "software_global.h" + +#include + +namespace paysages { +namespace software { + +struct RenderSub { + double start; + double end; + int count; + double previous_step; +}; + +/** + * Utility to keep track of render progress. + */ +class SOFTWARESHARED_EXPORT RenderProgress +{ +public: + RenderProgress(int count=1); + ~RenderProgress(); + + inline double get() const {return global;} + + void add(int value=1); + void enterSub(int count); + void exitSub(); + +private: + Mutex *lock; + double global; + double step; + std::stack subs; +}; + +} +} + +#endif // RENDERPROGRESS_H diff --git a/src/render/software/SkyRasterizer.cpp b/src/render/software/SkyRasterizer.cpp index 57866ae..0a429f6 100644 --- a/src/render/software/SkyRasterizer.cpp +++ b/src/render/software/SkyRasterizer.cpp @@ -8,25 +8,31 @@ #include "CloudsRenderer.h" #include "Rasterizer.h" #include "CanvasFragment.h" +#include "RenderProgress.h" #define SPHERE_SIZE 20000.0 -SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id, Color(0.9, 0.9, 1.0)) +SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id): + Rasterizer(renderer, progress, client_id, Color(0.9, 0.9, 1.0)) { } +int SkyRasterizer::prepareRasterization() +{ + res_i = renderer->render_quality * 40; + res_j = renderer->render_quality * 20; + + return res_i * res_j; +} + void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) { - int res_i, res_j; int i, j; double step_i, step_j; double current_i, current_j; Vector3 vertex1, vertex2, vertex3, vertex4; Vector3 camera_location, direction; - res_i = renderer->render_quality * 40; - res_j = renderer->render_quality * 20; step_i = M_PI * 2.0 / (double)res_i; step_j = M_PI / (double)res_j; @@ -68,6 +74,7 @@ void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas) /* TODO Triangles at poles */ pushQuad(canvas, vertex1, vertex4, vertex3, vertex2); } + progress->add(res_i); } } diff --git a/src/render/software/SkyRasterizer.h b/src/render/software/SkyRasterizer.h index 39b09ab..dc5a71b 100644 --- a/src/render/software/SkyRasterizer.h +++ b/src/render/software/SkyRasterizer.h @@ -11,10 +11,15 @@ namespace software { class SOFTWARESHARED_EXPORT SkyRasterizer: public Rasterizer { public: - SkyRasterizer(SoftwareRenderer* renderer, int client_id); + SkyRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id); + virtual int prepareRasterization() override; virtual void rasterizeToCanvas(CanvasPortion* canvas) override; virtual Color shadeFragment(const CanvasFragment &fragment) const override; + +private: + int res_i; + int res_j; }; } diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index 2a04bb0..8d9f440 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -13,6 +13,7 @@ #include "RenderConfig.h" #include "ColorProfile.h" #include "CanvasPreview.h" +#include "RenderProgress.h" SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery): SoftwareRenderer(scenery) @@ -21,12 +22,12 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery): finished = false; interrupted = false; canvas = new Canvas(); - progress = 0.0; + progress = new RenderProgress(); samples = 1; - rasterizers.push_back(new SkyRasterizer(this, 0)); - rasterizers.push_back(new WaterRasterizer(this, 1)); - rasterizers.push_back(new TerrainRasterizer(this, 2)); + rasterizers.push_back(new SkyRasterizer(this, progress, 0)); + rasterizers.push_back(new WaterRasterizer(this, progress, 1)); + rasterizers.push_back(new TerrainRasterizer(this, progress, 2)); current_work = NULL; } @@ -34,6 +35,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery): SoftwareCanvasRenderer::~SoftwareCanvasRenderer() { delete canvas; + delete progress; for (auto &rasterizer: rasterizers) { @@ -41,6 +43,11 @@ SoftwareCanvasRenderer::~SoftwareCanvasRenderer() } } +double SoftwareCanvasRenderer::getProgress() const +{ + return progress->get(); +} + void SoftwareCanvasRenderer::setConfig(const RenderConfig &config) { if (not started) @@ -62,7 +69,6 @@ void SoftwareCanvasRenderer::setSize(int width, int height, int samples) void SoftwareCanvasRenderer::render() { started = true; - progress = 0.0; render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); @@ -71,32 +77,33 @@ void SoftwareCanvasRenderer::render() // Iterate portions int nx = canvas->getHorizontalPortionCount(); int ny = canvas->getVerticalPortionCount(); - int i = 0; int n = nx * ny; + progress->enterSub(n); for (int y = 0; y < ny; y++) { for (int x = 0; x < nx; x++) { CanvasPortion *portion = canvas->at(x, y); + progress->enterSub(2); + if (not interrupted) { - progress_segment = 0.2 / (double)n; portion->preparePixels(); rasterize(portion); } if (not interrupted) { - progress_segment = 0.8 / (double)n; applyPixelShader(portion); } portion->discardPixels(); - i++; - progress = (double)i / (double)n; + + progress->exitSub(); } } + progress->exitSub(); finished = true; } @@ -126,11 +133,18 @@ bool SoftwareCanvasRenderer::saveToDisk(const std::string &filepath) const void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion) { + int count = 0; + for (auto &rasterizer:rasterizers) + { + count += rasterizer->prepareRasterization(); + } + + progress->enterSub(count); for (auto &rasterizer:rasterizers) { rasterizer->rasterizeToCanvas(portion); - progress += progress_segment / (double)rasterizers.size(); } + progress->exitSub(); } void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion) @@ -141,14 +155,8 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion) int chunks_y = (portion->getHeight() - 1) / chunk_size + 1; int units = chunks_x * chunks_y; - // Estimate chunks - int n = 0; - for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) - { - n += chunk_size / sub_chunk_size; - } - // Render chunks in parallel + progress->enterSub(portion->getWidth() * portion->getHeight()); for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) { if (interrupted) @@ -156,12 +164,12 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion) break; } - CanvasPixelShader shader(*this, portion, chunk_size, sub_chunk_size, chunks_x, chunks_y); + CanvasPixelShader shader(*this, portion, progress, chunk_size, sub_chunk_size, chunks_x, chunks_y); ParallelWork work(&shader, units); current_work = &work; work.perform(); current_work = NULL; - progress += progress_segment * (double)(chunk_size / sub_chunk_size) / (double)n; } + progress->exitSub(); } diff --git a/src/render/software/SoftwareCanvasRenderer.h b/src/render/software/SoftwareCanvasRenderer.h index df9d339..ef105b2 100644 --- a/src/render/software/SoftwareCanvasRenderer.h +++ b/src/render/software/SoftwareCanvasRenderer.h @@ -23,9 +23,13 @@ public: virtual ~SoftwareCanvasRenderer(); inline const Canvas *getCanvas() const {return canvas;} - inline double getProgress() const {return progress;} inline bool isFinished() const {return finished;} + /** + * Get the global rendering progress (0.0-1.0). + */ + double getProgress() const; + /** * Set the renderer configuration. */ @@ -72,8 +76,7 @@ protected: void applyPixelShader(CanvasPortion *portion); private: - double progress; - double progress_segment; + RenderProgress *progress; Canvas *canvas; int samples; diff --git a/src/render/software/TerrainRasterizer.cpp b/src/render/software/TerrainRasterizer.cpp index c66603b..503b259 100644 --- a/src/render/software/TerrainRasterizer.cpp +++ b/src/render/software/TerrainRasterizer.cpp @@ -9,9 +9,10 @@ #include "Scenery.h" #include "CanvasPortion.h" #include "CanvasFragment.h" +#include "RenderProgress.h" -TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id, Color(1.0, 0.9, 0.9)) +TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id): + Rasterizer(renderer, progress, client_id, Color(1.0, 0.9, 0.9)) { } @@ -22,11 +23,6 @@ static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z) void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail) { - if (detail < 1) - { - return; - } - double water_height = renderer->getWaterRenderer()->getHeightInfo().min_height; double startx = chunk->point_nw.x; @@ -40,6 +36,7 @@ void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* { renderQuad(canvas, startx + (double)i * size, startz + (double)j * size, size, water_height); } + progress->add(detail); } } @@ -125,12 +122,11 @@ static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChun } } -void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displaced) +int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced) { TerrainChunkInfo chunk; - int chunk_factor, chunk_count, i; + int chunk_factor, chunk_count, i, result; Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO); - double progress; double radius_int, radius_ext; double base_chunk_size, chunk_size; @@ -141,42 +137,69 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displace radius_int = 0.0; radius_ext = base_chunk_size; chunk_size = base_chunk_size; - progress = 0.0; + result = 0; double cx = cam.x - fmod(cam.x, base_chunk_size); double cz = cam.z - fmod(cam.x, base_chunk_size); while (radius_int < 20000.0) { - progress = radius_int / 20000.0; for (i = 0; i < chunk_count - 1; i++) { _getChunk(renderer, &chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced); - processChunk(canvas, &chunk, progress); + if (chunk.detail_hint > 0) + { + result += chunk.detail_hint * chunk.detail_hint; + if (canvas) + { + processChunk(canvas, &chunk); + } + } if (interrupted) { - return; + return result; } _getChunk(renderer, &chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced); - processChunk(canvas, &chunk, progress); + if (chunk.detail_hint > 0) + { + result += chunk.detail_hint * chunk.detail_hint; + if (canvas) + { + processChunk(canvas, &chunk); + } + } if (interrupted) { - return; + return result; } _getChunk(renderer, &chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced); - processChunk(canvas, &chunk, progress); + if (chunk.detail_hint > 0) + { + result += chunk.detail_hint * chunk.detail_hint; + if (canvas) + { + processChunk(canvas, &chunk); + } + } if (interrupted) { - return; + return result; } _getChunk(renderer, &chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced); - processChunk(canvas, &chunk, progress); + if (chunk.detail_hint > 0) + { + result += chunk.detail_hint * chunk.detail_hint; + if (canvas) + { + processChunk(canvas, &chunk); + } + } if (interrupted) { - return; + return result; } } @@ -190,16 +213,24 @@ void TerrainRasterizer::getTessellationInfo(CanvasPortion* canvas, bool displace radius_int = radius_ext; radius_ext += chunk_size; } + + return result; } -void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double) +void TerrainRasterizer::processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk) { tessellateChunk(canvas, chunk, chunk->detail_hint); } +int TerrainRasterizer::prepareRasterization() +{ + // TODO Chunks could be saved and reused in rasterizeToCanvas + return performTessellation(NULL, false); +} + void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { - getTessellationInfo(canvas, false); + performTessellation(canvas, false); } Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const diff --git a/src/render/software/TerrainRasterizer.h b/src/render/software/TerrainRasterizer.h index 5958355..4a34f2c 100644 --- a/src/render/software/TerrainRasterizer.h +++ b/src/render/software/TerrainRasterizer.h @@ -22,19 +22,28 @@ public: } TerrainChunkInfo; public: - TerrainRasterizer(SoftwareRenderer* renderer, int client_id); + TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id); + virtual int prepareRasterization() override; + virtual void rasterizeToCanvas(CanvasPortion* canvas) override; + virtual Color shadeFragment(const CanvasFragment &fragment) const override; + +private: /** - * Method called for each chunk tessellated by getTessellationInfo. + * Method called for each chunk tessellated by performTessellation. */ - void processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, double progress); + void processChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk); /** * Tessellate the terrain, calling processChunk for each chunk. * * The terrain will be broken in chunks, most detailed near the camera. + * + * Return the number of quads that has been pushed. + * + * *canvas* may be NULL to only simulate the tessellation. */ - void getTessellationInfo(CanvasPortion* canvas, bool displaced); + int performTessellation(CanvasPortion* canvas, bool displaced); /** * Tessellate a terrain chunk, pushing the quads in the render area. @@ -42,9 +51,6 @@ public: void tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail); void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height); - - virtual void rasterizeToCanvas(CanvasPortion* canvas) override; - virtual Color shadeFragment(const CanvasFragment &fragment) const override; }; } diff --git a/src/render/software/WaterRasterizer.cpp b/src/render/software/WaterRasterizer.cpp index 16c82b1..ddad775 100644 --- a/src/render/software/WaterRasterizer.cpp +++ b/src/render/software/WaterRasterizer.cpp @@ -3,9 +3,10 @@ #include "SoftwareRenderer.h" #include "WaterRenderer.h" #include "CanvasFragment.h" +#include "RenderProgress.h" -WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id): - Rasterizer(renderer, client_id, Color(0.9, 0.95, 1.0)) +WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id): + Rasterizer(renderer, progress, client_id, Color(0.9, 0.95, 1.0)) { } @@ -32,9 +33,25 @@ void WaterRasterizer::rasterizeQuad(CanvasPortion* canvas, double x, double z, d pushQuad(canvas, v1, v2, v3, v4); } +int WaterRasterizer::prepareRasterization() +{ + return performTessellation(NULL); +} + void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { - int chunk_factor, chunk_count, i; + performTessellation(canvas); +} + +Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const +{ + Vector3 location = fragment.getLocation(); + return renderer->getWaterRenderer()->getResult(location.x, location.z).final; +} + +int WaterRasterizer::performTessellation(CanvasPortion *canvas) +{ + int chunk_factor, chunk_count, i, result; Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO); double radius_int, radius_ext, base_chunk_size, chunk_size; @@ -44,6 +61,7 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) base_chunk_size *= 0.5; } + result = 0; chunk_factor = 1; chunk_count = 2; radius_int = 0.0; @@ -57,15 +75,23 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) { if (interrupted) { - return; + return result; } for (i = 0; i < chunk_count - 1; i++) { - rasterizeQuad(canvas, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size); - rasterizeQuad(canvas, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size); - rasterizeQuad(canvas, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size); - rasterizeQuad(canvas, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size); + result++; + if (canvas) + { + rasterizeQuad(canvas, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size); + rasterizeQuad(canvas, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size); + rasterizeQuad(canvas, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size); + rasterizeQuad(canvas, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size); + } + } + if (canvas) + { + progress->add(chunk_count - 1); } if (radius_int > 20.0 && chunk_count % 64 == 0 && (double)chunk_factor < radius_int / 20.0) @@ -78,10 +104,6 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas) radius_int = radius_ext; radius_ext += chunk_size; } -} -Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const -{ - Vector3 location = fragment.getLocation(); - return renderer->getWaterRenderer()->getResult(location.x, location.z).final; + return result; } diff --git a/src/render/software/WaterRasterizer.h b/src/render/software/WaterRasterizer.h index 4d587ae..4b4807c 100644 --- a/src/render/software/WaterRasterizer.h +++ b/src/render/software/WaterRasterizer.h @@ -11,12 +11,16 @@ namespace software { class WaterRasterizer: public Rasterizer { public: - WaterRasterizer(SoftwareRenderer* renderer, int client_id); + WaterRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id); void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size); + virtual int prepareRasterization() override; virtual void rasterizeToCanvas(CanvasPortion* canvas) override; virtual Color shadeFragment(const CanvasFragment &fragment) const override; + +private: + int performTessellation(CanvasPortion* canvas); }; } diff --git a/src/render/software/software.pro b/src/render/software/software.pro index db1fd25..0bc330a 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -50,7 +50,8 @@ SOURCES += SoftwareRenderer.cpp \ CanvasPictureWriter.cpp \ clouds/CloudModelAltoCumulus.cpp \ clouds/CloudModelCirrus.cpp \ - clouds/CloudModelCumuloNimbus.cpp + clouds/CloudModelCumuloNimbus.cpp \ + RenderProgress.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -90,7 +91,8 @@ HEADERS += SoftwareRenderer.h\ CanvasPictureWriter.h \ clouds/CloudModelAltoCumulus.h \ clouds/CloudModelCirrus.h \ - clouds/CloudModelCumuloNimbus.h + clouds/CloudModelCumuloNimbus.h \ + RenderProgress.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 637b85d..cce6d84 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -16,6 +16,7 @@ namespace software { class SoftwareRenderer; class SoftwareCanvasRenderer; class RenderConfig; + class RenderProgress; class FluidMediumManager; class FluidMediumInterface; diff --git a/src/tests/RenderProgress_Test.cpp b/src/tests/RenderProgress_Test.cpp new file mode 100644 index 0000000..f929f97 --- /dev/null +++ b/src/tests/RenderProgress_Test.cpp @@ -0,0 +1,33 @@ +#include "BaseTestCase.h" + +#include "RenderProgress.h" + +TEST(RenderProgress, RecursiveSections) +{ + RenderProgress progress(2); + EXPECT_DOUBLE_EQ(0.0, progress.get()); + + progress.enterSub(5); + EXPECT_DOUBLE_EQ(0.0, progress.get()); + + progress.add(); + EXPECT_DOUBLE_EQ(0.1, progress.get()); + + progress.add(2); + EXPECT_DOUBLE_EQ(0.3, progress.get()); + + progress.enterSub(4); + EXPECT_DOUBLE_EQ(0.3, progress.get()); + + progress.add(1); + EXPECT_DOUBLE_EQ(0.325, progress.get()); + + progress.exitSub(); + EXPECT_DOUBLE_EQ(0.4, progress.get()); + + progress.exitSub(); + EXPECT_DOUBLE_EQ(0.5, progress.get()); + + progress.add(1); + EXPECT_DOUBLE_EQ(1.0, progress.get()); +} diff --git a/src/tests/tests.pro b/src/tests/tests.pro index a1e661e..ce4b6a1 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -26,7 +26,8 @@ SOURCES += main.cpp \ DefinitionNode_Test.cpp \ FloatNode_Test.cpp \ DiffManager_Test.cpp \ - ColorHSL_Test.cpp + ColorHSL_Test.cpp \ + RenderProgress_Test.cpp HEADERS += \ BaseTestCase.h