a2ebc5268f
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
342 lines
6.9 KiB
C++
342 lines
6.9 KiB
C++
/*
|
|
* 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_time.h"
|
|
#include "util_thread.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
class Progress {
|
|
public:
|
|
Progress()
|
|
{
|
|
pixel_samples = 0;
|
|
total_pixel_samples = 0;
|
|
current_tile_sample = 0;
|
|
finished_tiles = 0;
|
|
start_time = time_dt();
|
|
render_start_time = time_dt();
|
|
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;
|
|
finished_tiles = 0;
|
|
start_time = time_dt();
|
|
render_start_time = time_dt();
|
|
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()
|
|
{
|
|
if(!cancel && cancel_cb)
|
|
cancel_cb();
|
|
|
|
return cancel;
|
|
}
|
|
|
|
string get_cancel_message()
|
|
{
|
|
thread_scoped_lock lock(progress_mutex);
|
|
return cancel_message;
|
|
}
|
|
|
|
void set_cancel_callback(function<void(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()
|
|
{
|
|
return error;
|
|
}
|
|
|
|
string get_error_message()
|
|
{
|
|
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();
|
|
}
|
|
|
|
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_)
|
|
{
|
|
thread_scoped_lock lock(progress_mutex);
|
|
|
|
total_time_ = time_dt() - start_time;
|
|
render_time_ = time_dt() - render_start_time;
|
|
}
|
|
|
|
void reset_sample()
|
|
{
|
|
thread_scoped_lock lock(progress_mutex);
|
|
|
|
pixel_samples = 0;
|
|
current_tile_sample = 0;
|
|
finished_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()
|
|
{
|
|
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()
|
|
{
|
|
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 finished_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_)
|
|
{
|
|
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(void)> function)
|
|
{
|
|
update_cb = function;
|
|
}
|
|
|
|
protected:
|
|
thread_mutex progress_mutex;
|
|
thread_mutex update_mutex;
|
|
function<void(void)> update_cb;
|
|
function<void(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 finished_tiles;
|
|
|
|
double start_time, render_start_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__ */
|
|
|