From a2ebc5268f2b98ee7335e0054c177c849a45cfba Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sat, 26 Nov 2016 04:22:34 +0100 Subject: 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 --- intern/cycles/app/cycles_standalone.cpp | 18 ++-- intern/cycles/blender/blender_session.cpp | 31 +------ intern/cycles/device/device.h | 1 + intern/cycles/device/device_cpu.cpp | 7 +- intern/cycles/device/device_cuda.cpp | 8 +- intern/cycles/device/device_multi.cpp | 8 ++ intern/cycles/device/device_network.cpp | 5 ++ intern/cycles/device/device_task.cpp | 12 ++- intern/cycles/device/device_task.h | 4 +- intern/cycles/device/opencl/opencl_mega.cpp | 6 +- intern/cycles/device/opencl/opencl_split.cpp | 4 + intern/cycles/render/bake.cpp | 20 ++--- intern/cycles/render/bake.h | 3 +- intern/cycles/render/session.cpp | 110 +++++++----------------- intern/cycles/render/session.h | 9 +- intern/cycles/render/tile.cpp | 37 ++++++-- intern/cycles/render/tile.h | 6 +- intern/cycles/util/util_progress.h | 123 ++++++++++++++++----------- intern/cycles/util/util_time.h | 8 +- 19 files changed, 216 insertions(+), 204 deletions(-) (limited to 'intern') 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& 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& tasks, int num, int max_size = 0); - void update_progress(RenderTile *rtile); + void update_progress(RenderTile *rtile, int pixel_samples = -1); function acquire_tile; - function update_progress_sample; + function update_progress_sample; function update_tile_sample; function release_tile; function 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 &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 > 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 update_cb; function 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_; -- cgit v1.2.3