diff options
Diffstat (limited to 'intern/cycles/util/progress.h')
-rw-r--r-- | intern/cycles/util/progress.h | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/intern/cycles/util/progress.h b/intern/cycles/util/progress.h new file mode 100644 index 00000000000..4b0ff08aa7e --- /dev/null +++ b/intern/cycles/util/progress.h @@ -0,0 +1,370 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_PROGRESS_H__ +#define __UTIL_PROGRESS_H__ + +/* Progress + * + * Simple class to communicate progress status messages, timing information, + * update notifications from a job running in another thread. All methods + * except for the constructor/destructor are thread safe. */ + +#include "util/function.h" +#include "util/string.h" +#include "util/thread.h" +#include "util/time.h" + +CCL_NAMESPACE_BEGIN + +class Progress { + public: + Progress() + { + pixel_samples = 0; + total_pixel_samples = 0; + current_tile_sample = 0; + rendered_tiles = 0; + denoised_tiles = 0; + start_time = time_dt(); + render_start_time = time_dt(); + end_time = 0.0; + status = "Initializing"; + substatus = ""; + sync_status = ""; + sync_substatus = ""; + update_cb = function_null; + cancel = false; + cancel_message = ""; + error = false; + error_message = ""; + cancel_cb = function_null; + } + + Progress(Progress &progress) + { + *this = progress; + } + + Progress &operator=(Progress &progress) + { + thread_scoped_lock lock(progress.progress_mutex); + + progress.get_status(status, substatus); + + pixel_samples = progress.pixel_samples; + total_pixel_samples = progress.total_pixel_samples; + current_tile_sample = progress.get_current_sample(); + + return *this; + } + + void reset() + { + pixel_samples = 0; + total_pixel_samples = 0; + current_tile_sample = 0; + rendered_tiles = 0; + denoised_tiles = 0; + start_time = time_dt(); + render_start_time = time_dt(); + end_time = 0.0; + status = "Initializing"; + substatus = ""; + sync_status = ""; + sync_substatus = ""; + cancel = false; + cancel_message = ""; + error = false; + error_message = ""; + } + + /* cancel */ + void set_cancel(const string &cancel_message_) + { + thread_scoped_lock lock(progress_mutex); + cancel_message = cancel_message_; + cancel = true; + } + + bool get_cancel() const + { + if (!cancel && cancel_cb) + cancel_cb(); + + return cancel; + } + + string get_cancel_message() const + { + thread_scoped_lock lock(progress_mutex); + return cancel_message; + } + + void set_cancel_callback(function<void()> function) + { + cancel_cb = function; + } + + /* error */ + void set_error(const string &error_message_) + { + thread_scoped_lock lock(progress_mutex); + error_message = error_message_; + error = true; + /* If error happens we also stop rendering. */ + cancel_message = error_message_; + cancel = true; + } + + bool get_error() const + { + return error; + } + + string get_error_message() const + { + thread_scoped_lock lock(progress_mutex); + return error_message; + } + + /* tile and timing information */ + + void set_start_time() + { + thread_scoped_lock lock(progress_mutex); + + start_time = time_dt(); + end_time = 0.0; + } + + void set_render_start_time() + { + thread_scoped_lock lock(progress_mutex); + + render_start_time = time_dt(); + } + + void add_skip_time(const scoped_timer &start_timer, bool only_render) + { + double skip_time = time_dt() - start_timer.get_start(); + + render_start_time += skip_time; + if (!only_render) { + start_time += skip_time; + } + } + + void get_time(double &total_time_, double &render_time_) const + { + thread_scoped_lock lock(progress_mutex); + + double time = (end_time > 0) ? end_time : time_dt(); + + total_time_ = time - start_time; + render_time_ = time - render_start_time; + } + + void set_end_time() + { + end_time = time_dt(); + } + + void reset_sample() + { + thread_scoped_lock lock(progress_mutex); + + pixel_samples = 0; + current_tile_sample = 0; + rendered_tiles = 0; + denoised_tiles = 0; + } + + void set_total_pixel_samples(uint64_t total_pixel_samples_) + { + thread_scoped_lock lock(progress_mutex); + + total_pixel_samples = total_pixel_samples_; + } + + float get_progress() const + { + thread_scoped_lock lock(progress_mutex); + + 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); + + pixel_samples += pixel_samples_; + current_tile_sample = tile_sample; + } + + void add_samples_update(uint64_t pixel_samples_, int tile_sample) + { + add_samples(pixel_samples_, tile_sample); + set_update(); + } + + void add_finished_tile(bool denoised) + { + thread_scoped_lock lock(progress_mutex); + + if (denoised) { + denoised_tiles++; + } + else { + rendered_tiles++; + } + } + + int get_current_sample() const + { + thread_scoped_lock lock(progress_mutex); + /* 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_rendered_tiles() const + { + thread_scoped_lock lock(progress_mutex); + return rendered_tiles; + } + + int get_denoised_tiles() const + { + thread_scoped_lock lock(progress_mutex); + return denoised_tiles; + } + + /* status messages */ + + void set_status(const string &status_, const string &substatus_ = "") + { + { + thread_scoped_lock lock(progress_mutex); + status = status_; + substatus = substatus_; + } + + set_update(); + } + + void set_substatus(const string &substatus_) + { + { + thread_scoped_lock lock(progress_mutex); + substatus = substatus_; + } + + set_update(); + } + + void set_sync_status(const string &status_, const string &substatus_ = "") + { + { + thread_scoped_lock lock(progress_mutex); + sync_status = status_; + sync_substatus = substatus_; + } + + set_update(); + } + + void set_sync_substatus(const string &substatus_) + { + { + thread_scoped_lock lock(progress_mutex); + sync_substatus = substatus_; + } + + set_update(); + } + + void get_status(string &status_, string &substatus_) const + { + thread_scoped_lock lock(progress_mutex); + + if (sync_status != "") { + status_ = sync_status; + substatus_ = sync_substatus; + } + else { + status_ = status; + substatus_ = substatus; + } + } + + /* callback */ + + void set_update() + { + if (update_cb) { + thread_scoped_lock lock(update_mutex); + update_cb(); + } + } + + void set_update_callback(function<void()> function) + { + update_cb = function; + } + + protected: + mutable thread_mutex progress_mutex; + mutable thread_mutex update_mutex; + function<void()> update_cb; + function<void()> cancel_cb; + + /* 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 rendered_tiles, denoised_tiles; + + double start_time, render_start_time; + /* End time written when render is done, so it doesn't keep increasing on redraws. */ + double end_time; + + string status; + string substatus; + + string sync_status; + string sync_substatus; + + volatile bool cancel; + string cancel_message; + + volatile bool error; + string error_message; +}; + +CCL_NAMESPACE_END + +#endif /* __UTIL_PROGRESS_H__ */ |