Restored (partially) render progress

This commit is contained in:
Michaël Lemaire 2014-08-20 15:58:37 +02:00
parent 18a669675f
commit 14e0320848
4 changed files with 38 additions and 34 deletions

View file

@ -116,11 +116,6 @@ DialogRender::~DialogRender()
delete pixbuf_lock; delete pixbuf_lock;
} }
void DialogRender::tellProgressChange(double value)
{
emit progressChanged(value);
}
void DialogRender::tellRenderEnded() void DialogRender::tellRenderEnded()
{ {
emit renderEnded(); emit renderEnded();
@ -133,6 +128,8 @@ void DialogRender::startRender()
_render_thread = new RenderThread(this, canvas_renderer); _render_thread = new RenderThread(this, canvas_renderer);
_render_thread->start(); _render_thread->start();
startTimer(100);
exec(); exec();
} }
@ -179,14 +176,15 @@ void DialogRender::loadLastRender()
exec(); exec();
} }
void DialogRender::applyProgress(double value) void DialogRender::timerEvent(QTimerEvent *)
{ {
double diff = difftime(time(NULL), _started); double diff = difftime(time(NULL), _started);
int hours = (int)floor(diff / 3600.0); int hours = (int)floor(diff / 3600.0);
int minutes = (int)floor((diff - 3600.0 * hours) / 60.0); int minutes = (int)floor((diff - 3600.0 * hours) / 60.0);
int seconds = (int)floor(diff - 3600.0 * hours - 60.0 * minutes); int seconds = (int)floor(diff - 3600.0 * hours - 60.0 * minutes);
_timer->setText(tr("%1:%2.%3").arg(hours).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0'))); _timer->setText(tr("%1:%2.%3").arg(hours).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')));
_progress->setValue((int)(value * 1000.0));
_progress->setValue((int)(canvas_renderer->getProgress() * 1000.0));
_progress->update(); _progress->update();
} }

View file

@ -18,25 +18,24 @@ class DialogRender : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer* renderer); explicit DialogRender(QWidget *parent, SoftwareCanvasRenderer *renderer);
~DialogRender(); ~DialogRender();
void tellProgressChange(double value);
void tellRenderEnded(); void tellRenderEnded();
void startRender(); void startRender();
void loadLastRender(); void loadLastRender();
virtual void timerEvent(QTimerEvent *event) override;
QImage* pixbuf; QImage* pixbuf;
QMutex* pixbuf_lock; QMutex* pixbuf_lock;
private slots: private slots:
void applyProgress(double value);
void saveRender(); void saveRender();
void applyRenderEnded(); void applyRenderEnded();
void toneMappingChanged(); void toneMappingChanged();
signals: signals:
void progressChanged(double value);
void renderEnded(); void renderEnded();
private: private:

View file

@ -17,6 +17,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer()
started = false; started = false;
interrupted = false; interrupted = false;
canvas = new Canvas(); canvas = new Canvas();
progress = 0.0;
rasterizers.push_back(new SkyRasterizer(this, 0)); rasterizers.push_back(new SkyRasterizer(this, 0));
rasterizers.push_back(new WaterRasterizer(this, 1)); rasterizers.push_back(new WaterRasterizer(this, 1));
@ -55,6 +56,7 @@ void SoftwareCanvasRenderer::setSize(int width, int height, int samples)
void SoftwareCanvasRenderer::render() void SoftwareCanvasRenderer::render()
{ {
started = true; started = true;
progress = 0.0;
render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight()); render_camera->setRenderSize(canvas->getWidth(), canvas->getHeight());
@ -63,6 +65,8 @@ void SoftwareCanvasRenderer::render()
// Iterate portions // Iterate portions
int nx = canvas->getHorizontalPortionCount(); int nx = canvas->getHorizontalPortionCount();
int ny = canvas->getVerticalPortionCount(); int ny = canvas->getVerticalPortionCount();
int i = 0;
int n = nx * ny;
for (int y = 0; y < ny; y++) for (int y = 0; y < ny; y++)
{ {
for (int x = 0; x < nx; x++) for (int x = 0; x < nx; x++)
@ -71,16 +75,20 @@ void SoftwareCanvasRenderer::render()
if (not interrupted) if (not interrupted)
{ {
progress_segment = 0.2 / (double)n;
portion->preparePixels(); portion->preparePixels();
rasterize(portion, true); rasterize(portion);
} }
if (not interrupted) if (not interrupted)
{ {
applyPixelShader(portion, true); progress_segment = 0.8 / (double)n;
applyPixelShader(portion);
} }
portion->discardPixels(); portion->discardPixels();
i++;
progress = (double)i / (double)n;
} }
} }
} }
@ -93,31 +101,27 @@ void SoftwareCanvasRenderer::interrupt()
{ {
current_work->interrupt(); current_work->interrupt();
} }
for (auto &rasterizer:getRasterizers()) for (auto &rasterizer:rasterizers)
{ {
rasterizer->interrupt(); rasterizer->interrupt();
} }
} }
const std::vector<Rasterizer *> &SoftwareCanvasRenderer::getRasterizers() const
{
return rasterizers;
}
const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const
{ {
return *(getRasterizers()[client_id]); return *(rasterizers[client_id]);
} }
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded) void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion)
{ {
for (auto &rasterizer:getRasterizers()) for (auto &rasterizer:rasterizers)
{ {
rasterizer->rasterizeToCanvas(portion); rasterizer->rasterizeToCanvas(portion);
progress += progress_segment / (double)rasterizers.size();
} }
} }
void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threaded) void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion)
{ {
// Subdivide in chunks // Subdivide in chunks
int chunk_size = 64; int chunk_size = 64;
@ -125,6 +129,13 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threa
int chunks_y = (portion->getHeight() - 1) / chunk_size + 1; int chunks_y = (portion->getHeight() - 1) / chunk_size + 1;
int units = chunks_x * chunks_y; 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 // Render chunks in parallel
for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2) for (int sub_chunk_size = chunk_size; sub_chunk_size >= 1; sub_chunk_size /= 2)
{ {
@ -139,5 +150,6 @@ void SoftwareCanvasRenderer::applyPixelShader(CanvasPortion *portion, bool threa
current_work = &work; current_work = &work;
work.perform(); work.perform();
current_work = NULL; current_work = NULL;
progress += progress_segment * (double)(chunk_size / sub_chunk_size) / (double)n;
} }
} }

View file

@ -23,6 +23,7 @@ public:
virtual ~SoftwareCanvasRenderer(); virtual ~SoftwareCanvasRenderer();
inline const Canvas *getCanvas() const {return canvas;} inline const Canvas *getCanvas() const {return canvas;}
inline double getProgress() const {return progress;}
/** /**
* Set the renderer configuration. * Set the renderer configuration.
@ -46,11 +47,6 @@ public:
*/ */
void interrupt(); void interrupt();
/**
* @brief Get the list of objects that can be rasterized to polygons on a canvas.
*/
virtual const std::vector<Rasterizer*> &getRasterizers() const;
/** /**
* Get a rasterizer by its client id. * Get a rasterizer by its client id.
*/ */
@ -59,19 +55,18 @@ public:
protected: protected:
/** /**
* @brief Rasterize the scenery into a canvas portion. * @brief Rasterize the scenery into a canvas portion.
*
* If 'threaded' is true, the rasterization will take advantage of multiple CPU cores.
*/ */
void rasterize(CanvasPortion *portion, bool threaded=false); void rasterize(CanvasPortion *portion);
/** /**
* @brief Apply pixel shader to fragments stored in the CanvasPortion. * @brief Apply pixel shader to fragments stored in the CanvasPortion.
*
* If 'threaded' is true, the shader will take advantage of multiple CPU cores.
*/ */
void applyPixelShader(CanvasPortion *portion, bool threaded=true); void applyPixelShader(CanvasPortion *portion);
private: private:
double progress;
double progress_segment;
Canvas *canvas; Canvas *canvas;
std::vector<Rasterizer*> rasterizers; std::vector<Rasterizer*> rasterizers;
bool started; bool started;