Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Stockner <lukas.stockner@freenet.de>2016-11-26 06:22:34 +0300
committerLukas Stockner <lukas.stockner@freenet.de>2016-12-03 07:02:21 +0300
commita2ebc5268f2b98ee7335e0054c177c849a45cfba (patch)
treef1c08ab691cc93b08df0a387b037d1e0a45e9a53
parent35d490b3f13c75e9a62cb30f3842ed38a27f6dbc (diff)
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far: - It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image. - Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased. This patch fixes both problems: First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time. The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels. Along with that, some unused variables were removed from the Progress and Session classes. Reviewers: brecht, sergey, #cycles Subscribers: brecht, candreacchio, sergey Differential Revision: https://developer.blender.org/D2214
-rw-r--r--intern/cycles/app/cycles_standalone.cpp18
-rw-r--r--intern/cycles/blender/blender_session.cpp31
-rw-r--r--intern/cycles/device/device.h1
-rw-r--r--intern/cycles/device/device_cpu.cpp7
-rw-r--r--intern/cycles/device/device_cuda.cpp8
-rw-r--r--intern/cycles/device/device_multi.cpp8
-rw-r--r--intern/cycles/device/device_network.cpp5
-rw-r--r--intern/cycles/device/device_task.cpp12
-rw-r--r--intern/cycles/device/device_task.h4
-rw-r--r--intern/cycles/device/opencl/opencl_mega.cpp6
-rw-r--r--intern/cycles/device/opencl/opencl_split.cpp4
-rw-r--r--intern/cycles/render/bake.cpp20
-rw-r--r--intern/cycles/render/bake.h3
-rw-r--r--intern/cycles/render/session.cpp110
-rw-r--r--intern/cycles/render/session.h9
-rw-r--r--intern/cycles/render/tile.cpp37
-rw-r--r--intern/cycles/render/tile.h6
-rw-r--r--intern/cycles/util/util_progress.h123
-rw-r--r--intern/cycles/util/util_time.h8
19 files changed, 216 insertions, 204 deletions
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index b21e8630cdb..9816d614a7c 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -72,20 +72,17 @@ static void session_print(const string& str)
static void session_print_status()
{
- int sample, tile;
- double total_time, sample_time, render_time;
string status, substatus;
/* get status */
- sample = options.session->progress.get_sample();
- options.session->progress.get_tile(tile, total_time, sample_time, render_time);
+ float progress = options.session->progress.get_progress();
options.session->progress.get_status(status, substatus);
if(substatus != "")
status += ": " + substatus;
/* print status */
- status = string_printf("Sample %d %s", sample, status.c_str());
+ status = string_printf("Progress %05.2f %s", (double) progress*100, status.c_str());
session_print(status);
}
@@ -167,13 +164,12 @@ static void display_info(Progress& progress)
latency = (elapsed - last);
last = elapsed;
- int sample, tile;
- double total_time, sample_time, render_time;
+ double total_time, sample_time;
string status, substatus;
- sample = progress.get_sample();
- progress.get_tile(tile, total_time, sample_time, render_time);
+ progress.get_time(total_time, sample_time);
progress.get_status(status, substatus);
+ float progress_val = progress.get_progress();
if(substatus != "")
status += ": " + substatus;
@@ -184,10 +180,10 @@ static void display_info(Progress& progress)
"%s"
" Time: %.2f"
" Latency: %.4f"
- " Sample: %d"
+ " Progress: %05.2f"
" Average: %.4f"
" Interactive: %s",
- status.c_str(), total_time, latency, sample, sample_time, interactive.c_str());
+ status.c_str(), total_time, latency, (double) progress_val*100, sample_time, interactive.c_str());
view_display_info(str.c_str());
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index e16cea0ebaf..71c1eefe65f 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -930,38 +930,13 @@ void BlenderSession::get_status(string& status, string& substatus)
void BlenderSession::get_progress(float& progress, double& total_time, double& render_time)
{
- double tile_time;
- int tile, sample, samples_per_tile;
- int tile_total = session->tile_manager.state.num_tiles;
- int samples = session->tile_manager.state.sample + 1;
- int total_samples = session->tile_manager.get_num_effective_samples();
-
- session->progress.get_tile(tile, total_time, render_time, tile_time);
-
- sample = session->progress.get_sample();
- samples_per_tile = session->tile_manager.get_num_effective_samples();
-
- if(background && samples_per_tile && tile_total)
- progress = ((float)sample / (float)(tile_total * samples_per_tile));
- else if(!background && samples > 0 && total_samples != INT_MAX)
- progress = ((float)samples) / total_samples;
- else
- progress = 0.0;
+ session->progress.get_time(total_time, render_time);
+ progress = session->progress.get_progress();
}
void BlenderSession::update_bake_progress()
{
- float progress;
- int sample, samples_per_task, parts_total;
-
- sample = session->progress.get_sample();
- samples_per_task = scene->bake_manager->num_samples;
- parts_total = scene->bake_manager->num_parts;
-
- if(samples_per_task)
- progress = ((float)sample / (float)(parts_total * samples_per_task));
- else
- progress = 0.0;
+ float progress = session->progress.get_progress();
if(progress != last_progress) {
b_engine.update_progress(progress);
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index b9bdffa2618..988ad10607d 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -220,6 +220,7 @@ public:
DeviceInfo info;
virtual const string& error_message() { return error_msg; }
bool have_error() { return !error_message().empty(); }
+ virtual bool show_samples() const { return false; }
/* statistics */
Stats &stats;
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index aed86d8d853..c8e001ec2fd 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -112,6 +112,11 @@ public:
task_pool.stop();
}
+ virtual bool show_samples() const
+ {
+ return (TaskScheduler::num_threads() == 1);
+ }
+
void mem_alloc(device_memory& mem, MemoryType /*type*/)
{
mem.device_pointer = mem.data_pointer;
@@ -275,7 +280,7 @@ public:
tile.sample = sample + 1;
- task.update_progress(&tile);
+ task.update_progress(&tile, tile.w*tile.h);
}
task.release_tile(tile);
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index fbb97f78e70..233f94be1bf 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -115,6 +115,12 @@ public:
return path_exists(cubins_path);
}
+ virtual bool show_samples() const
+ {
+ /* The CUDADevice only processes one tile at a time, so showing samples is fine. */
+ return true;
+ }
+
/*#ifdef NDEBUG
#define cuda_abort()
#else
@@ -1267,7 +1273,7 @@ public:
tile.sample = sample + 1;
- task->update_progress(&tile);
+ task->update_progress(&tile, tile.w*tile.h);
}
task->release_tile(tile);
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 48fd159d508..31b800640d3 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -89,6 +89,14 @@ public:
return error_msg;
}
+ virtual bool show_samples() const
+ {
+ if(devices.size() > 1) {
+ return false;
+ }
+ return devices.front().device->show_samples();
+ }
+
bool load_kernels(const DeviceRequestedFeatures& requested_features)
{
foreach(SubDevice& sub, devices)
diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp
index 3eb5ad2d2db..53eef6cf199 100644
--- a/intern/cycles/device/device_network.cpp
+++ b/intern/cycles/device/device_network.cpp
@@ -51,6 +51,11 @@ public:
thread_mutex rpc_lock;
+ virtual bool show_samples() const
+ {
+ return false;
+ }
+
NetworkDevice(DeviceInfo& info, Stats &stats, const char *address)
: Device(info, stats, true), socket(io_service)
{
diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp
index 1f1128a28f8..48d18035c13 100644
--- a/intern/cycles/device/device_task.cpp
+++ b/intern/cycles/device/device_task.cpp
@@ -19,6 +19,8 @@
#include "device_task.h"
+#include "buffers.h"
+
#include "util_algorithm.h"
#include "util_time.h"
@@ -99,14 +101,18 @@ void DeviceTask::split(list<DeviceTask>& tasks, int num, int max_size)
}
}
-void DeviceTask::update_progress(RenderTile *rtile)
+void DeviceTask::update_progress(RenderTile *rtile, int pixel_samples)
{
if((type != PATH_TRACE) &&
(type != SHADER))
return;
- if(update_progress_sample)
- update_progress_sample();
+ if(update_progress_sample) {
+ if(pixel_samples == -1) {
+ pixel_samples = shader_w;
+ }
+ update_progress_sample(pixel_samples, rtile? rtile->sample : 0);
+ }
if(update_tile_sample) {
double current_time = time_dt();
diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h
index 8423e83bdfd..8bd54c3d2b0 100644
--- a/intern/cycles/device/device_task.h
+++ b/intern/cycles/device/device_task.h
@@ -56,10 +56,10 @@ public:
int get_subtask_count(int num, int max_size = 0);
void split(list<DeviceTask>& tasks, int num, int max_size = 0);
- void update_progress(RenderTile *rtile);
+ void update_progress(RenderTile *rtile, int pixel_samples = -1);
function<bool(Device *device, RenderTile&)> acquire_tile;
- function<void(void)> update_progress_sample;
+ function<void(long, int)> update_progress_sample;
function<void(RenderTile&)> update_tile_sample;
function<void(RenderTile&)> release_tile;
function<bool(void)> get_cancel;
diff --git a/intern/cycles/device/opencl/opencl_mega.cpp b/intern/cycles/device/opencl/opencl_mega.cpp
index 369c086df57..6ea7619e022 100644
--- a/intern/cycles/device/opencl/opencl_mega.cpp
+++ b/intern/cycles/device/opencl/opencl_mega.cpp
@@ -39,6 +39,10 @@ public:
{
}
+ virtual bool show_samples() const {
+ return true;
+ }
+
virtual void load_kernels(const DeviceRequestedFeatures& /*requested_features*/,
vector<OpenCLProgram*> &programs)
{
@@ -120,7 +124,7 @@ public:
tile.sample = sample + 1;
- task->update_progress(&tile);
+ task->update_progress(&tile, tile.w*tile.h);
}
/* Complete kernel execution before release tile */
diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp
index 239e73a40fd..3c3c2150128 100644
--- a/intern/cycles/device/opencl/opencl_split.cpp
+++ b/intern/cycles/device/opencl/opencl_split.cpp
@@ -247,6 +247,10 @@ public:
}
}
+ virtual bool show_samples() const {
+ return false;
+ }
+
/* Split kernel utility functions. */
size_t get_tex_size(const char *tex_name)
{
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 13310a61761..d9a297002c6 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -135,20 +135,16 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
{
size_t num_pixels = bake_data->size();
- progress.reset_sample();
- this->num_parts = 0;
+ int num_samples = is_aa_pass(shader_type)? scene->integrator->aa_samples : 1;
- /* calculate the total parts for the progress bar */
+ /* calculate the total pixel samples for the progress bar */
+ total_pixel_samples = 0;
for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) {
size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit);
-
- DeviceTask task(DeviceTask::SHADER);
- task.shader_w = shader_size;
-
- this->num_parts += device->get_split_task_count(task);
+ total_pixel_samples += shader_size * num_samples;
}
-
- this->num_samples = is_aa_pass(shader_type)? scene->integrator->aa_samples : 1;
+ progress.reset_sample();
+ progress.set_total_pixel_samples(total_pixel_samples);
for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) {
size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit);
@@ -187,9 +183,9 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
task.shader_x = 0;
task.offset = shader_offset;
task.shader_w = d_output.size();
- task.num_samples = this->num_samples;
+ task.num_samples = num_samples;
task.get_cancel = function_bind(&Progress::get_cancel, &progress);
- task.update_progress_sample = function_bind(&Progress::increment_sample_update, &progress);
+ task.update_progress_sample = function_bind(&Progress::add_samples_update, &progress, _1, _2);
device->task_add(task);
device->task_wait();
diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h
index 8377e387197..25f5eb3c897 100644
--- a/intern/cycles/render/bake.h
+++ b/intern/cycles/render/bake.h
@@ -73,8 +73,7 @@ public:
bool need_update;
- int num_samples;
- int num_parts;
+ int total_pixel_samples;
private:
BakeData *m_bake_data;
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 9d8c9fed7af..8e902243211 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -67,10 +67,7 @@ Session::Session(const SessionParams& params_)
session_thread = NULL;
scene = NULL;
- start_time = 0.0;
reset_time = 0.0;
- preview_time = 0.0;
- paused_time = 0.0;
last_update_time = 0.0;
delayed_reset.do_reset = false;
@@ -201,12 +198,10 @@ void Session::run_gpu()
{
bool tiles_written = false;
- start_time = time_dt();
reset_time = time_dt();
- paused_time = 0.0;
last_update_time = time_dt();
- progress.set_render_start_time(start_time + paused_time);
+ progress.set_render_start_time();
while(!progress.get_cancel()) {
/* advance to next tile */
@@ -233,13 +228,9 @@ void Session::run_gpu()
update_status_time(pause, no_tiles);
while(1) {
- double pause_start = time_dt();
+ scoped_timer pause_timer;
pause_cond.wait(pause_lock);
- paused_time += time_dt() - pause_start;
-
- if(!params.background)
- progress.set_start_time(start_time + paused_time);
- progress.set_render_start_time(start_time + paused_time);
+ progress.add_skip_time(pause_timer, params.background);
update_status_time(pause, no_tiles);
progress.set_update();
@@ -255,7 +246,9 @@ void Session::run_gpu()
if(!no_tiles) {
/* update scene */
+ scoped_timer update_timer;
update_scene();
+ progress.add_skip_time(update_timer, params.background);
if(!device->error_message().empty())
progress.set_error(device->error_message());
@@ -523,13 +516,9 @@ void Session::run_cpu()
update_status_time(pause, no_tiles);
while(1) {
- double pause_start = time_dt();
+ scoped_timer pause_timer;
pause_cond.wait(pause_lock);
- paused_time += time_dt() - pause_start;
-
- if(!params.background)
- progress.set_start_time(start_time + paused_time);
- progress.set_render_start_time(start_time + paused_time);
+ progress.add_skip_time(pause_timer, params.background);
update_status_time(pause, no_tiles);
progress.set_update();
@@ -550,7 +539,9 @@ void Session::run_cpu()
thread_scoped_lock buffers_lock(buffers_mutex);
/* update scene */
+ scoped_timer update_timer;
update_scene();
+ progress.add_skip_time(update_timer, params.background);
if(!device->error_message().empty())
progress.set_error(device->error_message());
@@ -718,14 +709,14 @@ void Session::reset_(BufferParams& buffer_params, int samples)
}
tile_manager.reset(buffer_params, samples);
+ progress.reset_sample();
- start_time = time_dt();
- preview_time = 0.0;
- paused_time = 0.0;
+ bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX;
+ progress.set_total_pixel_samples(show_progress? tile_manager.state.total_pixel_samples : 0);
if(!params.background)
- progress.set_start_time(start_time);
- progress.set_render_start_time(start_time);
+ progress.set_start_time();
+ progress.set_render_start_time();
}
void Session::reset(BufferParams& buffer_params, int samples)
@@ -827,61 +818,40 @@ void Session::update_scene()
void Session::update_status_time(bool show_pause, bool show_done)
{
- int sample = tile_manager.state.sample;
- int resolution = tile_manager.state.resolution_divider;
- int num_tiles = tile_manager.state.num_tiles;
+ int progressive_sample = tile_manager.state.sample;
+ int num_samples = tile_manager.get_num_effective_samples();
+
int tile = tile_manager.state.num_rendered_tiles;
+ int num_tiles = tile_manager.state.num_tiles;
/* update status */
string status, substatus;
if(!params.progressive) {
- const int progress_sample = progress.get_sample(),
- num_samples = tile_manager.get_num_effective_samples();
- const bool is_gpu = params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL;
- const bool is_multidevice = params.device.multi_devices.size() > 1;
const bool is_cpu = params.device.type == DEVICE_CPU;
- const bool is_last_tile = (num_samples * num_tiles - progress_sample) < num_samples;
+ const bool is_last_tile = (progress.get_finished_tiles() + 1) == num_tiles;
substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
- if((is_gpu && !is_multidevice && !device->info.use_split_kernel) ||
- (is_cpu && (num_tiles == 1 || is_last_tile)))
+ if(device->show_samples() || (is_cpu && is_last_tile))
{
- /* When using split-kernel (OpenCL) each thread in a tile will be working on a different
- * sample. Can't display sample number when device uses split-kernel
+ /* Some devices automatically support showing the sample number:
+ * - CUDADevice
+ * - OpenCLDevice when using the megakernel (the split kernel renders multiple samples at the same time, so the current sample isn't really defined)
+ * - CPUDevice when using one thread
+ * For these devices, the current sample is always shown.
+ *
+ * The other option is when the last tile is currently being rendered by the CPU.
*/
-
- /* when rendering on GPU multithreading happens within single tile, as in
- * tiles are handling sequentially and in this case we could display
- * currently rendering sample number
- * this helps a lot from feedback point of view.
- * also display the info on CPU, when using 1 tile only
- */
-
- int status_sample = progress_sample;
- if(tile > 1) {
- /* sample counter is global for all tiles, subtract samples
- * from already finished tiles to get sample counter for
- * current tile only
- */
- if(is_cpu && is_last_tile && num_tiles > 1) {
- status_sample = num_samples - (num_samples * num_tiles - progress_sample);
- }
- else {
- status_sample -= (tile - 1) * num_samples;
- }
- }
-
- substatus += string_printf(", Sample %d/%d", status_sample, num_samples);
+ substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples);
}
}
else if(tile_manager.num_samples == INT_MAX)
- substatus = string_printf("Path Tracing Sample %d", sample+1);
+ substatus = string_printf("Path Tracing Sample %d", progressive_sample+1);
else
substatus = string_printf("Path Tracing Sample %d/%d",
- sample+1,
- tile_manager.get_num_effective_samples());
+ progressive_sample+1,
+ num_samples);
if(show_pause) {
status = "Paused";
@@ -895,22 +865,6 @@ void Session::update_status_time(bool show_pause, bool show_done)
}
progress.set_status(status, substatus);
-
- /* update timing */
- if(preview_time == 0.0 && resolution == 1)
- preview_time = time_dt();
-
- double tile_time = (tile == 0 || sample == 0)? 0.0: (time_dt() - preview_time - paused_time) / sample;
-
- /* negative can happen when we pause a bit before rendering, can discard that */
- if(preview_time < 0.0) preview_time = 0.0;
-
- progress.set_tile(tile, tile_time);
-}
-
-void Session::update_progress_sample()
-{
- progress.increment_sample();
}
void Session::path_trace()
@@ -922,7 +876,7 @@ void Session::path_trace()
task.release_tile = function_bind(&Session::release_tile, this, _1);
task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
- task.update_progress_sample = function_bind(&Session::update_progress_sample, this);
+ task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2);
task.need_finish_queue = params.progressive_refine;
task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH;
task.requested_tile_size = params.tile_size;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 1db4692e171..c7ff1446171 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -145,6 +145,10 @@ public:
void device_free();
+ /* Returns the rendering progress or 0 if no progress can be determined
+ * (for example, when rendering with unlimited samples). */
+ float get_progress();
+
protected:
struct DelayedReset {
thread_mutex mutex;
@@ -173,8 +177,6 @@ protected:
void update_tile_sample(RenderTile& tile);
void release_tile(RenderTile& tile);
- void update_progress_sample();
-
bool device_use_gl;
thread *session_thread;
@@ -194,10 +196,7 @@ protected:
bool kernels_loaded;
- double start_time;
double reset_time;
- double preview_time;
- double paused_time;
/* progressive refine */
double last_update_time;
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 3a6dfea11a7..e59d0c843a3 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -108,36 +108,57 @@ TileManager::~TileManager()
{
}
-void TileManager::reset(BufferParams& params_, int num_samples_)
+static int get_divider(int w, int h, int start_resolution)
{
- params = params_;
-
int divider = 1;
- int w = params.width, h = params.height;
-
if(start_resolution != INT_MAX) {
while(w*h > start_resolution*start_resolution) {
w = max(1, w/2);
h = max(1, h/2);
- divider *= 2;
+ divider <<= 1;
}
}
+ return divider;
+}
- num_samples = num_samples_;
+void TileManager::reset(BufferParams& params_, int num_samples_)
+{
+ params = params_;
+
+ set_samples(num_samples_);
state.buffer = BufferParams();
state.sample = range_start_sample - 1;
state.num_tiles = 0;
state.num_rendered_tiles = 0;
state.num_samples = 0;
- state.resolution_divider = divider;
+ state.resolution_divider = get_divider(params.width, params.height, start_resolution);
state.tiles.clear();
}
void TileManager::set_samples(int num_samples_)
{
num_samples = num_samples_;
+
+ /* No real progress indication is possible when using unlimited samples. */
+ if(num_samples == INT_MAX) {
+ state.total_pixel_samples = 0;
+ }
+ else {
+ uint64_t pixel_samples = 0;
+ /* While rendering in the viewport, the initial preview resolution is increased to the native resolution
+ * before the actual rendering begins. Therefore, additional pixel samples will be rendered. */
+ int divider = get_divider(params.width, params.height, start_resolution) / 2;
+ while(divider > 1) {
+ int image_w = max(1, params.width/divider);
+ int image_h = max(1, params.height/divider);
+ pixel_samples += image_w * image_h;
+ divider >>= 1;
+ }
+
+ state.total_pixel_samples = pixel_samples + get_num_effective_samples() * params.width*params.height;
+ }
}
/* If sliced is false, splits image into tiles and assigns equal amount of tiles to every render device.
diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h
index af1b1ed8b0f..5d92ebac355 100644
--- a/intern/cycles/render/tile.h
+++ b/intern/cycles/render/tile.h
@@ -64,6 +64,10 @@ public:
int resolution_divider;
int num_tiles;
int num_rendered_tiles;
+
+ /* Total samples over all pixels: Generally num_samples*num_pixels,
+ * but can be higher due to the initial resolution division for previews. */
+ uint64_t total_pixel_samples;
/* This vector contains a list of tiles for every logical device in the session.
* In each list, the tiles are sorted according to the tile order setting. */
vector<list<Tile> > tiles;
@@ -91,7 +95,7 @@ public:
/* Number to samples in the rendering range. */
int range_num_samples;
- /* get number of actual samples to render. */
+ /* Get number of actual samples to render. */
int get_num_effective_samples();
protected:
diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h
index 4ae1d61dd17..14215056840 100644
--- a/intern/cycles/util/util_progress.h
+++ b/intern/cycles/util/util_progress.h
@@ -34,12 +34,12 @@ class Progress {
public:
Progress()
{
- tile = 0;
- sample = 0;
+ pixel_samples = 0;
+ total_pixel_samples = 0;
+ current_tile_sample = 0;
+ finished_tiles = 0;
start_time = time_dt();
- total_time = 0.0;
- render_time = 0.0;
- tile_time = 0.0;
+ render_start_time = time_dt();
status = "Initializing";
substatus = "";
sync_status = "";
@@ -62,22 +62,22 @@ public:
thread_scoped_lock lock(progress.progress_mutex);
progress.get_status(status, substatus);
- progress.get_tile(tile, total_time, render_time, tile_time);
- sample = progress.get_sample();
+ pixel_samples = progress.pixel_samples;
+ total_pixel_samples = progress.total_pixel_samples;
+ current_tile_sample = progress.get_current_sample();
return *this;
}
void reset()
{
- tile = 0;
- sample = 0;
+ pixel_samples = 0;
+ total_pixel_samples = 0;
+ current_tile_sample = 0;
+ finished_tiles = 0;
start_time = time_dt();
render_start_time = time_dt();
- total_time = 0.0;
- render_time = 0.0;
- tile_time = 0.0;
status = "Initializing";
substatus = "";
sync_status = "";
@@ -139,69 +139,93 @@ public:
/* tile and timing information */
- void set_start_time(double start_time_)
+ void set_start_time()
{
thread_scoped_lock lock(progress_mutex);
- start_time = start_time_;
+ start_time = time_dt();
}
- void set_render_start_time(double render_start_time_)
+ void set_render_start_time()
{
thread_scoped_lock lock(progress_mutex);
- render_start_time = render_start_time_;
+ render_start_time = time_dt();
}
- void set_tile(int tile_, double tile_time_)
+ void add_skip_time(const scoped_timer &start_timer, bool only_render)
{
- thread_scoped_lock lock(progress_mutex);
+ double skip_time = time_dt() - start_timer.get_start();
- tile = tile_;
- total_time = time_dt() - start_time;
- render_time = time_dt() - render_start_time;
- tile_time = tile_time_;
+ render_start_time += skip_time;
+ if(!only_render) {
+ start_time += skip_time;
+ }
}
- void get_tile(int& tile_, double& total_time_, double& render_time_, double& tile_time_)
+ void get_time(double& total_time_, double& render_time_)
{
thread_scoped_lock lock(progress_mutex);
- tile_ = tile;
- total_time_ = (total_time > 0.0)? total_time: 0.0;
- render_time_ = (render_time > 0.0)? render_time: 0.0;
- tile_time_ = tile_time;
+ total_time_ = time_dt() - start_time;
+ render_time_ = time_dt() - render_start_time;
}
- void get_time(double& total_time_, double& render_time_)
+ void reset_sample()
{
- total_time_ = (total_time > 0.0)? total_time: 0.0;
- render_time_ = (render_time > 0.0)? render_time: 0.0;
+ thread_scoped_lock lock(progress_mutex);
+
+ pixel_samples = 0;
+ current_tile_sample = 0;
+ finished_tiles = 0;
}
- void reset_sample()
+ void set_total_pixel_samples(uint64_t total_pixel_samples_)
{
thread_scoped_lock lock(progress_mutex);
- sample = 0;
+ total_pixel_samples = total_pixel_samples_;
}
- void increment_sample()
+ float get_progress()
+ {
+ if(total_pixel_samples > 0) {
+ return ((float) pixel_samples) / total_pixel_samples;
+ }
+ return 0.0f;
+ }
+
+ void add_samples(uint64_t pixel_samples_, int tile_sample)
{
thread_scoped_lock lock(progress_mutex);
- sample++;
+ pixel_samples += pixel_samples_;
+ current_tile_sample = tile_sample;
}
- void increment_sample_update()
+ void add_samples_update(uint64_t pixel_samples_, int tile_sample)
{
- increment_sample();
+ add_samples(pixel_samples_, tile_sample);
set_update();
}
- int get_sample()
+ void add_finished_tile()
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ finished_tiles++;
+ }
+
+ int get_current_sample()
+ {
+ /* Note that the value here always belongs to the last tile that updated,
+ * so it's only useful if there is only one active tile. */
+ return current_tile_sample;
+ }
+
+ int get_finished_tiles()
{
- return sample;
+ return finished_tiles;
}
/* status messages */
@@ -212,8 +236,6 @@ public:
thread_scoped_lock lock(progress_mutex);
status = status_;
substatus = substatus_;
- total_time = time_dt() - start_time;
- render_time = time_dt() - render_start_time;
}
set_update();
@@ -224,8 +246,6 @@ public:
{
thread_scoped_lock lock(progress_mutex);
substatus = substatus_;
- total_time = time_dt() - start_time;
- render_time = time_dt() - render_start_time;
}
set_update();
@@ -237,8 +257,6 @@ public:
thread_scoped_lock lock(progress_mutex);
sync_status = status_;
sync_substatus = substatus_;
- total_time = time_dt() - start_time;
- render_time = time_dt() - render_start_time;
}
set_update();
@@ -250,8 +268,6 @@ public:
{
thread_scoped_lock lock(progress_mutex);
sync_substatus = substatus_;
- total_time = time_dt() - start_time;
- render_time = time_dt() - render_start_time;
}
set_update();
@@ -292,12 +308,19 @@ protected:
function<void(void)> update_cb;
function<void(void)> cancel_cb;
- int tile; /* counter for rendered tiles */
- int sample; /* counter of rendered samples, global for all tiles */
+ /* pixel_samples counts how many samples have been rendered over all pixel, not just per pixel.
+ * This makes the progress estimate more accurate when tiles with different sizes are used.
+ *
+ * total_pixel_samples is the total amount of pixel samples that will be rendered. */
+ uint64_t pixel_samples, total_pixel_samples;
+ /* Stores the current sample count of the last tile that called the update function.
+ * It's used to display the sample count if only one tile is active. */
+ int current_tile_sample;
+ /* Stores the number of tiles that's already finished.
+ * Used to determine whether all but the last tile are finished rendering, in which case the current_tile_sample is displayed. */
+ int finished_tiles;
double start_time, render_start_time;
- double total_time, render_time;
- double tile_time;
string status;
string substatus;
diff --git a/intern/cycles/util/util_time.h b/intern/cycles/util/util_time.h
index a5b074bffa0..65798244111 100644
--- a/intern/cycles/util/util_time.h
+++ b/intern/cycles/util/util_time.h
@@ -29,7 +29,7 @@ void time_sleep(double t);
class scoped_timer {
public:
- explicit scoped_timer(double *value) : value_(value)
+ explicit scoped_timer(double *value = NULL) : value_(value)
{
time_start_ = time_dt();
}
@@ -40,6 +40,12 @@ public:
*value_ = time_dt() - time_start_;
}
}
+
+ double get_start() const
+ {
+ return time_start_;
+ }
+
protected:
double *value_;
double time_start_;