Blender  V3.3
render_scheduler.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #pragma once
5 
7 #include "integrator/denoiser.h" /* For DenoiseParams. */
8 #include "session/buffers.h"
9 #include "util/string.h"
10 
12 
13 class SessionParams;
14 class TileManager;
15 
16 class RenderWork {
17  public:
19 
20  /* Initialize render buffers.
21  * Includes steps like zeroing the buffer on the device, and optional reading of pixels from the
22  * baking target. */
23  bool init_render_buffers = false;
24 
25  /* Path tracing samples information. */
26  struct {
27  int start_sample = 0;
28  int num_samples = 0;
29  int sample_offset = 0;
31 
32  struct {
33  /* Check for convergency and filter the mask. */
34  bool filter = false;
35 
36  float threshold = 0.0f;
37 
38  /* Reset convergency flag when filtering, forcing a re-check of whether pixel did converge. */
39  bool reset = false;
41 
42  struct {
43  bool postprocess = false;
45 
46  /* Work related on the current tile. */
47  struct {
48  /* Write render buffers of the current tile.
49  *
50  * It is up to the path trace to decide whether writing should happen via user-provided
51  * callback into the rendering software, or via tile manager into a partial file. */
52  bool write = false;
53 
54  bool denoise = false;
55  } tile;
56 
57  /* Work related on the full-frame render buffer. */
58  struct {
59  /* Write full render result.
60  * Implies reading the partial file from disk. */
61  bool write = false;
62  } full;
63 
64  /* Display which is used to visualize render result. */
65  struct {
66  /* Display needs to be updated for the new render. */
67  bool update = false;
68 
69  /* Display can use denoised result if available. */
70  bool use_denoised_result = true;
72 
73  /* Re-balance multi-device scheduling after rendering this work.
74  * Note that the scheduler does not know anything about devices, so if there is only a single
75  * device used, then it is up for the PathTracer to ignore the balancing. */
76  bool rebalance = false;
77 
78  /* Conversion to bool, to simplify checks about whether there is anything to be done for this
79  * work. */
80  inline operator bool() const
81  {
82  return path_trace.num_samples || adaptive_sampling.filter || display.update || tile.denoise ||
83  tile.write || full.write;
84  }
85 };
86 
88  public:
89  RenderScheduler(TileManager &tile_manager, const SessionParams &params);
90 
91  /* Specify whether cryptomatte-related works are to be scheduled. */
92  void set_need_schedule_cryptomatte(bool need_schedule_cryptomatte);
93 
94  /* Allows to disable work re-balancing works, allowing to schedule as much to a single device
95  * as possible. */
96  void set_need_schedule_rebalance(bool need_schedule_rebalance);
97 
98  bool is_background() const;
99 
101  void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling);
102 
103  bool is_adaptive_sampling_used() const;
104 
105  /* Start sample for path tracing.
106  * The scheduler will schedule work using this sample as the first one. */
107  void set_start_sample(int start_sample);
108  int get_start_sample() const;
109 
110  /* Number of samples to render, starting from start sample.
111  * The scheduler will schedule work in the range of
112  * [start_sample, start_sample + num_samples - 1], inclusively. */
113  void set_num_samples(int num_samples);
114  int get_num_samples() const;
115 
116  void set_sample_offset(int sample_offset);
117  int get_sample_offset() const;
118 
119  /* Time limit for the path tracing tasks, in minutes.
120  * Zero disables the limit. */
121  void set_time_limit(double time_limit);
122  double get_time_limit() const;
123 
124  /* Get sample up to which rendering has been done.
125  * This is an absolute 0-based value.
126  *
127  * For example, if start sample is 10 and 5 samples were rendered, then this call will
128  * return 14.
129  *
130  * If there were no samples rendered, then the behavior is undefined. */
131  int get_rendered_sample() const;
132 
133  /* Get number of samples rendered within the current scheduling session.
134  *
135  * For example, if start sample is 10 and 5 samples were rendered, then this call will
136  * return 5.
137  *
138  * Note that this is based on the scheduling information. In practice this means that if someone
139  * requested for work to render the scheduler considers the work done. */
140  int get_num_rendered_samples() const;
141 
142  /* Reset scheduler, indicating that rendering will happen from scratch.
143  * Resets current rendered state, as well as scheduling information. */
144  void reset(const BufferParams &buffer_params, int num_samples, int sample_offset);
145 
146  /* Reset scheduler upon switching to a next tile.
147  * Will keep the same number of samples and full-frame render parameters, but will reset progress
148  * and allow schedule renders works from the beginning of the new tile. */
149  void reset_for_next_tile();
150 
151  /* Reschedule adaptive sampling work when all pixels did converge.
152  * If there is nothing else to be done for the adaptive sampling (pixels did converge to the
153  * final threshold) then false is returned and the render scheduler will stop scheduling path
154  * tracing works. Otherwise will modify the work's adaptive sampling settings to continue with
155  * a lower threshold. */
157 
158  /* Reschedule adaptive sampling work when the device is mostly on idle, but not all pixels yet
159  * converged.
160  * If re-scheduling is not possible (adaptive sampling is happening with the final threshold, and
161  * the path tracer is to finish the current pixels) then false is returned. */
162  bool render_work_reschedule_on_idle(RenderWork &render_work);
163 
164  /* Reschedule work when rendering has been requested to cancel.
165  *
166  * Will skip all work which is not needed anymore because no more samples will be added (for
167  * example, adaptive sampling filtering and convergence check will be skipped).
168  * Will enable all work needed to make sure all passes are communicated to the software.
169  *
170  * NOTE: Should be used before passing work to `PathTrace::render_samples()`. */
171  void render_work_reschedule_on_cancel(RenderWork &render_work);
172 
174 
175  /* Report that the path tracer started to work, after scene update and loading kernels. */
176  void report_work_begin(const RenderWork &render_work);
177 
178  /* Report time (in seconds) which corresponding part of work took. */
179  void report_path_trace_time(const RenderWork &render_work, double time, bool is_cancelled);
180  void report_path_trace_occupancy(const RenderWork &render_work, float occupancy);
181  void report_adaptive_filter_time(const RenderWork &render_work, double time, bool is_cancelled);
182  void report_denoise_time(const RenderWork &render_work, double time);
183  void report_display_update_time(const RenderWork &render_work, double time);
184  void report_rebalance_time(const RenderWork &render_work, double time, bool balance_changed);
185 
186  /* Generate full multi-line report of the rendering process, including rendering parameters,
187  * times, and so on. */
188  string full_report() const;
189 
190  protected:
191  /* Check whether all work has been scheduled and time limit was not exceeded.
192  *
193  * NOTE: Tricky bit: if the time limit was reached the done() is considered to be true, but some
194  * extra work needs to be scheduled to denoise and write final result. */
195  bool done() const;
196 
197  /* Update scheduling state for a newly scheduled work.
198  * Takes care of things like checking whether work was ever denoised, tile was written and states
199  * like that. */
200  void update_state_for_render_work(const RenderWork &render_work);
201 
202  /* Returns true if any work was scheduled. */
203  bool set_postprocess_render_work(RenderWork *render_work);
204 
205  /* Set work which is to be performed after all tiles has been rendered. */
206  void set_full_frame_render_work(RenderWork *render_work);
207 
208  /* Update start resolution divider based on the accumulated timing information, preserving nice
209  * feeling navigation feel. */
211 
212  /* Calculate desired update interval in seconds based on the current timings and settings.
213  * Will give an interval which provides good feeling updates during viewport navigation. */
215 
216  /* Check whether denoising is active during interactive update while resolution divider is not
217  * unit. */
218  bool is_denoise_active_during_update() const;
219 
220  /* Heuristic which aims to give perceptually pleasant update of display interval in a way that at
221  * lower samples and near the beginning of rendering, updates happen more often, but with higher
222  * number of samples and later in the render, updates happen less often but device occupancy
223  * goes higher. */
227  int num_rendered_samples) const;
228 
229  /* Calculate number of samples which can be rendered within current desired update interval which
230  * is calculated by `guess_update_interval_in_seconds()`. */
232 
233  /* Get start sample and the number of samples which are to be path traces in the current work. */
234  int get_start_sample_to_path_trace() const;
235  int get_num_samples_to_path_trace() const;
236 
237  /* Calculate how many samples there are to be rendered for the very first path trace after reset.
238  */
239  int get_num_samples_during_navigation(int resolution_divier) const;
240 
241  /* Whether adaptive sampling convergence check and filter is to happen. */
242  bool work_need_adaptive_filter() const;
243 
244  /* Calculate threshold for adaptive sampling. */
245  float work_adaptive_threshold() const;
246 
247  /* Check whether current work needs denoising.
248  * Denoising is not needed if the denoiser is not configured, or when denoising is happening too
249  * often.
250  *
251  * The delayed will be true when the denoiser is configured for use, but it was delayed for a
252  * later sample, to reduce overhead.
253  *
254  * ready_to_display will be false if we may have a denoised result that is outdated due to
255  * increased samples. */
256  bool work_need_denoise(bool &delayed, bool &ready_to_display);
257 
258  /* Check whether current work need to update display.
259  *
260  * The `denoiser_delayed` is what `work_need_denoise()` returned as delayed denoiser flag. */
261  bool work_need_update_display(const bool denoiser_delayed);
262 
263  /* Check whether it is time to perform rebalancing for the render work, */
264  bool work_need_rebalance();
265 
266  /* Check whether timing of the given work are usable to store timings in the `first_render_time_`
267  * for the resolution divider calculation. */
269 
270  /* Check whether timing report about the given work need to reset accumulated average time. */
271  bool work_report_reset_average(const RenderWork &render_work);
272 
273  /* Check whether render time limit has been reached (or exceeded), and if so store related
274  * information in the state so that rendering is considered finished, and is possible to report
275  * average render time information. */
277 
278  /* Helper class to keep track of task timing.
279  *
280  * Contains two parts: wall time and average. The wall time is an actual wall time of how long it
281  * took to complete all tasks of a type. Is always advanced when PathTracer reports time update.
282  *
283  * The average time is used for scheduling purposes. It is estimated to be a time of how long it
284  * takes to perform task on the final resolution. */
286  public:
287  inline void reset()
288  {
289  total_wall_time_ = 0.0;
290 
292  num_average_times_ = 0;
293  }
294 
295  inline void add_wall(double time)
296  {
298  }
299 
300  inline void add_average(double time, int num_measurements = 1)
301  {
303  num_average_times_ += num_measurements;
304  }
305 
306  inline double get_wall() const
307  {
308  return total_wall_time_;
309  }
310 
311  inline double get_average() const
312  {
313  if (num_average_times_ == 0) {
314  return 0;
315  }
317  }
318 
319  inline void reset_average()
320  {
322  num_average_times_ = 0;
323  }
324 
325  protected:
326  double total_wall_time_ = 0.0;
327 
330  };
331 
332  struct {
334 
335  /* Number of rendered samples on top of the start sample. */
337 
338  /* Point in time the latest PathTraceDisplay work has been scheduled. */
340  /* Value of -1 means display was never updated. */
342 
343  /* Point in time at which last rebalance has been performed. */
344  double last_rebalance_time = 0.0;
345 
346  /* Number of rebalance works which has been requested to be performed.
347  * The path tracer might ignore the work if there is a single device rendering. */
349 
350  /* Number of rebalance works handled which did change balance across devices. */
352 
354 
355  /* Denotes whether the latest performed rebalance work cause an actual rebalance of work across
356  * devices. */
358 
359  /* Threshold for adaptive sampling which will be scheduled to work when not using progressive
360  * noise floor. */
362 
368 
369  bool path_trace_finished = false;
370  bool time_limit_reached = false;
371 
372  /* Time at which rendering started and finished. */
373  double start_render_time = 0.0;
374  double end_render_time = 0.0;
375 
376  /* Measured occupancy of the render devices measured normalized to the number of samples.
377  *
378  * In a way it is "trailing": when scheduling new work this occupancy is measured when the
379  * previous work was rendered. */
381  float occupancy = 1.0f;
383 
384  /* Timing of tasks which were performed at the very first render work at 100% of the
385  * resolution. This timing information is used to estimate resolution divider for fats
386  * navigation. */
387  struct {
389  double denoise_time;
392 
398 
399  /* Whether cryptomatte-related work will be scheduled. */
401 
402  /* Whether to schedule device load rebalance works.
403  * Rebalancing requires some special treatment for update intervals and such, so if it's known
404  * that the rebalance will be ignored (due to single-device rendering i.e.) is better to fully
405  * ignore rebalancing logic. */
407 
408  /* Path tracing work will be scheduled for samples from within
409  * [start_sample_, start_sample_ + num_samples_ - 1] range, inclusively. */
410  int start_sample_ = 0;
411  int num_samples_ = 0;
412 
413  int sample_offset_ = 0;
414 
415  /* Limit in seconds for how long path tracing is allowed to happen.
416  * Zero means no limit is applied. */
417  double time_limit_ = 0.0;
418 
419  /* Headless rendering without interface. */
420  bool headless_;
421 
422  /* Background (offline) rendering. */
424 
425  /* Pixel size is used to force lower resolution render for final pass. Useful for retina or other
426  * types of hi-dpi displays. */
427  int pixel_size_ = 1;
428 
430 
433 
435 
436  /* Progressively lower adaptive sampling threshold level, keeping the image at a uniform noise
437  * level. */
439 
440  /* Default value for the resolution divider which will be used when there is no render time
441  * information available yet.
442  * It is also what defines the upper limit of the automatically calculated resolution divider. */
444 
445  /* Initial resolution divider which will be used on render scheduler reset. */
447 
448  /* Calculate smallest resolution divider which will bring down actual rendering time below the
449  * desired one. This call assumes linear dependency of render time from number of pixels
450  * (quadratic dependency from the resolution divider): resolution divider of 2 brings render time
451  * down by a factor of 4. */
452  int calculate_resolution_divider_for_time(double desired_time, double actual_time);
453 };
454 
455 int calculate_resolution_divider_for_resolution(int width, int height, int resolution);
456 
457 int calculate_resolution_for_divider(int width, int height, int resolution_divider);
458 
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
void add_average(double time, int num_measurements=1)
int calculate_resolution_divider_for_time(double desired_time, double actual_time)
AdaptiveSampling adaptive_sampling_
DenoiseParams denoiser_params_
void update_state_for_render_work(const RenderWork &render_work)
void report_display_update_time(const RenderWork &render_work, double time)
float work_adaptive_threshold() const
int calculate_num_samples_per_update() const
int get_rendered_sample() const
void set_time_limit(double time_limit)
bool work_need_update_display(const bool denoiser_delayed)
BufferParams buffer_params_
void set_sample_offset(int sample_offset)
struct RenderScheduler::@1247 first_render_time_
void report_adaptive_filter_time(const RenderWork &render_work, double time, bool is_cancelled)
void set_need_schedule_rebalance(bool need_schedule_rebalance)
double guess_display_update_interval_in_seconds() const
bool work_need_denoise(bool &delayed, bool &ready_to_display)
bool work_need_adaptive_filter() const
struct RenderScheduler::@1246 state_
int get_num_rendered_samples() const
string full_report() const
bool need_schedule_rebalance_works_
void reset(const BufferParams &buffer_params, int num_samples, int sample_offset)
bool is_denoise_active_during_update() const
int get_num_samples_during_navigation(int resolution_divier) const
bool set_postprocess_render_work(RenderWork *render_work)
void report_rebalance_time(const RenderWork &render_work, double time, bool balance_changed)
double get_time_limit() const
double guess_display_update_interval_in_seconds_for_num_samples_no_limit(int num_rendered_samples) const
bool work_is_usable_for_first_render_estimation(const RenderWork &render_work)
void report_denoise_time(const RenderWork &render_work, double time)
bool is_adaptive_sampling_used() const
double last_display_update_time
void set_denoiser_params(const DenoiseParams &params)
bool use_progressive_noise_floor_
double guess_display_update_interval_in_seconds_for_num_samples(int num_rendered_samples) const
double path_trace_per_sample
bool render_work_reschedule_on_idle(RenderWork &render_work)
int get_num_samples() const
TimeWithAverage adaptive_filter_time_
TimeWithAverage rebalance_time_
int get_sample_offset() const
int default_start_resolution_divider_
void report_path_trace_time(const RenderWork &render_work, double time, bool is_cancelled)
bool need_rebalance_at_next_work
TimeWithAverage display_update_time_
void set_full_frame_render_work(RenderWork *render_work)
double guess_viewport_navigation_update_interval_in_seconds() const
void update_start_resolution_divider()
void set_num_samples(int num_samples)
void report_path_trace_occupancy(const RenderWork &render_work, float occupancy)
void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling)
bool render_work_reschedule_on_converge(RenderWork &render_work)
TileManager & tile_manager_
bool work_report_reset_average(const RenderWork &render_work)
TimeWithAverage path_trace_time_
void set_start_sample(int start_sample)
int get_start_sample_to_path_trace() const
int get_num_samples_to_path_trace() const
void render_work_reschedule_on_cancel(RenderWork &render_work)
float adaptive_sampling_threshold
bool last_work_tile_was_denoised
void report_work_begin(const RenderWork &render_work)
TimeWithAverage denoise_time_
void set_need_schedule_cryptomatte(bool need_schedule_cryptomatte)
int get_start_sample() const
RenderWork get_render_work()
RenderScheduler(TileManager &tile_manager, const SessionParams &params)
bool is_background() const
int resolution_divider
struct RenderWork::@1244 full
bool use_denoised_result
struct RenderWork::@1245 display
bool init_render_buffers
struct RenderWork::@1242 cryptomatte
struct RenderWork::@1241 adaptive_sampling
struct RenderWork::@1240 path_trace
struct RenderWork::@1243 tile
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
double time
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global float int int int int ccl_global const float int int int int int int int int int int int int num_samples
int calculate_resolution_divider_for_resolution(int width, int height, int resolution)
int calculate_resolution_for_divider(int width, int height, int resolution_divider)