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;
}
void DialogRender::tellProgressChange(double value)
{
emit progressChanged(value);
}
void DialogRender::tellRenderEnded()
{
emit renderEnded();
@ -133,6 +128,8 @@ void DialogRender::startRender()
_render_thread = new RenderThread(this, canvas_renderer);
_render_thread->start();
startTimer(100);
exec();
}
@ -179,14 +176,15 @@ void DialogRender::loadLastRender()
exec();
}
void DialogRender::applyProgress(double value)
void DialogRender::timerEvent(QTimerEvent *)
{
double diff = difftime(time(NULL), _started);
int hours = (int)floor(diff / 3600.0);
int minutes = (int)floor((diff - 3600.0 * hours) / 60.0);
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')));
_progress->setValue((int)(value * 1000.0));
_progress->setValue((int)(canvas_renderer->getProgress() * 1000.0));
_progress->update();
}

View file

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

View file

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

View file

@ -23,6 +23,7 @@ public:
virtual ~SoftwareCanvasRenderer();
inline const Canvas *getCanvas() const {return canvas;}
inline double getProgress() const {return progress;}
/**
* Set the renderer configuration.
@ -46,11 +47,6 @@ public:
*/
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.
*/
@ -59,19 +55,18 @@ public:
protected:
/**
* @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.
*
* 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:
double progress;
double progress_segment;
Canvas *canvas;
std::vector<Rasterizer*> rasterizers;
bool started;