Blender V4.5
render_scheduler.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
9
10#include "session/buffers.h"
11
12#include "util/string.h"
13
15
16class SessionParams;
17class TileManager;
18
20 public:
22
23 /* Initialize render buffers.
24 * Includes steps like zeroing the buffer on the device, and optional reading of pixels from the
25 * baking target. */
26 bool init_render_buffers = false;
27
28 /* Path tracing samples information. */
29 struct {
30 int start_sample = 0;
31 int num_samples = 0;
34
35 struct {
36 /* Check for convergency and filter the mask. */
37 bool filter = false;
38
39 float threshold = 0.0f;
40
41 /* Reset convergency flag when filtering, forcing a re-check of whether pixel did converge. */
42 bool reset = false;
44
45 struct {
46 bool postprocess = false;
48
49 /* Work related on the current tile. */
50 struct {
51 /* Write render buffers of the current tile.
52 *
53 * It is up to the path trace to decide whether writing should happen via user-provided
54 * callback into the rendering software, or via tile manager into a partial file. */
55 bool write = false;
56
57 bool denoise = false;
59
60 /* Work related on the full-frame render buffer. */
61 struct {
62 /* Write full render result.
63 * Implies reading the partial file from disk. */
64 bool write = false;
66
67 /* Display which is used to visualize render result. */
68 struct {
69 /* Display needs to be updated for the new render. */
70 bool update = false;
71
72 /* Display can use denoised result if available. */
75
76 /* Re-balance multi-device scheduling after rendering this work.
77 * Note that the scheduler does not know anything about devices, so if there is only a single
78 * device used, then it is up for the PathTracer to ignore the balancing. */
79 bool rebalance = false;
80
81 /* Conversion to bool, to simplify checks about whether there is anything to be done for this
82 * work. */
83 operator bool() const
84 {
85 return path_trace.num_samples || adaptive_sampling.filter || display.update || tile.denoise ||
86 tile.write || full.write;
87 }
88};
89
91 public:
92 RenderScheduler(TileManager &tile_manager, const SessionParams &params);
93
94 /* Specify whether cryptomatte-related works are to be scheduled. */
95 void set_need_schedule_cryptomatte(bool need_schedule_cryptomatte);
96
97 /* Allows to disable work re-balancing works, allowing to schedule as much to a single device
98 * as possible. */
99 void set_need_schedule_rebalance(bool need_schedule_rebalance);
100
101 bool is_background() const;
102
104 bool is_denoiser_gpu_used() const;
105
106 void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling);
107 bool is_adaptive_sampling_used() const;
108
109 /* Setup parameters defining the sampling range.
110 *
111 * It is a single function setting up multiple parameters because there are inter-dependencies
112 * between these parameters.
113 *
114 * In simple cases the subset is not used and the given num_samples samples is rendered, and the
115 * subset length and offset are ignored.
116 *
117 * It is possible to render a subset of the overall samples. This is typically used to distribute
118 * rendering of a single frame across multiple computers. This subset rendering is enabled by
119 * setting use_sample_subset=true, and giving the desired offset and length of the subset. The
120 * subset offset is a 0-based sample index to start sampling from, and the length is the number
121 * of samples to render in this subset.
122 *
123 * When the subset rendering is enabled, num_samples is expected to be set to the overall number
124 * of samples to be rendered, and it is internally used to clamp the number of samples rendered
125 * by a subset. */
126 void set_sample_params(const int num_samples,
127 const bool use_sample_subset,
128 const int sample_subset_offset,
129 const int sample_subset_length);
130
131 /* Number of samples to render, starting from start sample.
132 * The scheduler will schedule work in the range of
133 * [start_sample, start_sample + num_samples - 1], inclusively. */
134 int get_num_samples() const;
135
136 /* For sample subset rendering, extra offset to be added to sample index
137 * for the sampling pattern to be shifted. */
138 int get_sample_offset() const;
139
140 /* Time limit for the path tracing tasks, in minutes.
141 * Zero disables the limit. */
142 void set_time_limit(const double time_limit);
143 double get_time_limit() const;
144
145 /* Get sample up to which rendering has been done.
146 * This is an absolute 0-based value.
147 *
148 * For example, if start sample is 10 and 5 samples were rendered, then this call will
149 * return 14.
150 *
151 * If there were no samples rendered, then the behavior is undefined. */
152 int get_rendered_sample() const;
153
154 /* Get number of samples rendered within the current scheduling session.
155 *
156 * For example, if start sample is 10 and 5 samples were rendered, then this call will
157 * return 5.
158 *
159 * Note that this is based on the scheduling information. In practice this means that if someone
160 * requested for work to render the scheduler considers the work done. */
161 int get_num_rendered_samples() const;
162
163 /* Reset scheduler, indicating that rendering will happen from scratch.
164 * Resets current rendered state, as well as scheduling information. */
165 void reset(const BufferParams &buffer_params);
166
167 /* Reset scheduler upon switching to a next tile.
168 * Will keep the same number of samples and full-frame render parameters, but will reset progress
169 * and allow schedule renders works from the beginning of the new tile. */
170 void reset_for_next_tile();
171
172 /* Reschedule adaptive sampling work when all pixels did converge.
173 * If there is nothing else to be done for the adaptive sampling (pixels did converge to the
174 * final threshold) then false is returned and the render scheduler will stop scheduling path
175 * tracing works. Otherwise will modify the work's adaptive sampling settings to continue with
176 * a lower threshold. */
178
179 /* Reschedule adaptive sampling work when the device is mostly on idle, but not all pixels yet
180 * converged.
181 * If re-scheduling is not possible (adaptive sampling is happening with the final threshold, and
182 * the path tracer is to finish the current pixels) then false is returned. */
184
185 /* Reschedule work when rendering has been requested to cancel.
186 *
187 * Will skip all work which is not needed anymore because no more samples will be added (for
188 * example, adaptive sampling filtering and convergence check will be skipped).
189 * Will enable all work needed to make sure all passes are communicated to the software.
190 *
191 * NOTE: Should be used before passing work to `PathTrace::render_samples()`. */
193
195
196 /* Report that the path tracer started to work, after scene update and loading kernels. */
197 void report_work_begin(const RenderWork &render_work);
198
199 /* Report time (in seconds) which corresponding part of work took. */
200 void report_path_trace_time(const RenderWork &render_work, const double time, bool is_cancelled);
201 void report_path_trace_occupancy(const RenderWork &render_work, const float occupancy);
202 void report_adaptive_filter_time(const RenderWork &render_work,
203 const double time,
204 bool is_cancelled);
205 void report_denoise_time(const RenderWork &render_work, const double time);
206 void report_display_update_time(const RenderWork &render_work, const double time);
207 void report_rebalance_time(const RenderWork &render_work,
208 const double time,
209 bool balance_changed);
210
211 /* Generate full multi-line report of the rendering process, including rendering parameters,
212 * times, and so on. */
213 string full_report() const;
214
215 void set_limit_samples_per_update(const int limit_samples);
216
217 protected:
218 /* Check whether all work has been scheduled and time limit was not exceeded.
219 *
220 * NOTE: Tricky bit: if the time limit was reached the done() is considered to be true, but some
221 * extra work needs to be scheduled to denoise and write final result. */
222 bool done() const;
223
224 /* Update scheduling state for a newly scheduled work.
225 * Takes care of things like checking whether work was ever denoised, tile was written and states
226 * like that. */
227 void update_state_for_render_work(const RenderWork &render_work);
228
229 /* Returns true if any work was scheduled. */
230 bool set_postprocess_render_work(RenderWork *render_work);
231
232 /* Set work which is to be performed after all tiles has been rendered. */
233 void set_full_frame_render_work(RenderWork *render_work);
234
235 /* Update start resolution divider based on the accumulated timing information, preserving nice
236 * feeling navigation feel. */
238
239 /* Calculate desired update interval in seconds based on the current timings and settings.
240 * Will give an interval which provides good feeling updates during viewport navigation. */
242
243 /* Check whether denoising is active during interactive update while resolution divider is not
244 * unit. */
246
247 /* Heuristic which aims to give perceptually pleasant update of display interval in a way that at
248 * lower samples and near the beginning of rendering, updates happen more often, but with higher
249 * number of samples and later in the render, updates happen less often but device occupancy
250 * goes higher. */
253 const int num_rendered_samples) const;
255 int num_rendered_samples) const;
256
257 /* Calculate number of samples which can be rendered within current desired update interval which
258 * is calculated by `guess_update_interval_in_seconds()`. */
260
261 /* Get start sample and the number of samples which are to be path traces in the current work. */
264
265 /* Calculate how many samples there are to be rendered for the very first path trace after reset.
266 */
268
269 /* Whether adaptive sampling convergence check and filter is to happen. */
270 bool work_need_adaptive_filter() const;
271
272 /* Calculate threshold for adaptive sampling. */
273 float work_adaptive_threshold() const;
274
275 /* Check whether current work needs denoising.
276 * Denoising is not needed if the denoiser is not configured, or when denoising is happening too
277 * often.
278 *
279 * The delayed will be true when the denoiser is configured for use, but it was delayed for a
280 * later sample, to reduce overhead.
281 *
282 * ready_to_display will be false if we may have a denoised result that is outdated due to
283 * increased samples. */
284 bool work_need_denoise(bool &delayed, bool &ready_to_display);
285
286 /* Check whether current work need to update display.
287 *
288 * The `denoiser_delayed` is what `work_need_denoise()` returned as delayed denoiser flag. */
289 bool work_need_update_display(const bool denoiser_delayed);
290
291 /* Check whether it is time to perform rebalancing for the render work, */
292 bool work_need_rebalance();
293
294 /* Check whether timing of the given work are usable to store timings in the `first_render_time_`
295 * for the resolution divider calculation. */
297
298 /* Check whether timing report about the given work need to reset accumulated average time. */
299 bool work_report_reset_average(const RenderWork &render_work);
300
301 /* Check whether render time limit has been reached (or exceeded), and if so store related
302 * information in the state so that rendering is considered finished, and is possible to report
303 * average render time information. */
305
306 /* Helper class to keep track of task timing.
307 *
308 * Contains two parts: wall time and average. The wall time is an actual wall time of how long it
309 * took to complete all tasks of a type. Is always advanced when PathTracer reports time update.
310 *
311 * The average time is used for scheduling purposes. It is estimated to be a time of how long it
312 * takes to perform task on the final resolution. */
314 public:
315 void reset()
316 {
317 total_wall_time_ = 0.0;
318
321
322 last_sample_time_ = 0.0;
323 }
324
325 void add_wall(const double time)
326 {
327 total_wall_time_ += time;
328 }
329
330 void add_average(const double time, const int num_measurements = 1)
331 {
333 num_average_times_ += num_measurements;
334 last_sample_time_ = time / num_measurements;
335 }
336
337 double get_wall() const
338 {
339 return total_wall_time_;
340 }
341
342 double get_average() const
343 {
344 if (num_average_times_ == 0) {
345 return 0;
346 }
348 }
349
350 double get_last_sample_time() const
351 {
352 return last_sample_time_;
353 }
354
356 {
359 }
360
361 protected:
362 double total_wall_time_ = 0.0;
363
366
367 double last_sample_time_ = 0.0;
368 };
369
370 struct {
371 bool user_is_navigating = false;
372
374
375 /* Number of rendered samples on top of the start sample. */
377
378 /* Point in time the latest PathTraceDisplay work has been scheduled. */
380 /* Value of -1 means display was never updated. */
382
383 /* Point in time at which last rebalance has been performed. */
385
386 /* Number of rebalance works which has been requested to be performed.
387 * The path tracer might ignore the work if there is a single device rendering. */
389
390 /* Number of rebalance works handled which did change balance across devices. */
392
394
395 /* Denotes whether the latest performed rebalance work cause an actual rebalance of work across
396 * devices. */
398
399 /* Threshold for adaptive sampling which will be scheduled to work when not using progressive
400 * noise floor. */
402
408
410 bool time_limit_reached = false;
411
412 /* Time at which rendering started and finished. */
413 double start_render_time = 0.0;
414 double end_render_time = 0.0;
415
416 /* Measured occupancy of the render devices measured normalized to the number of samples.
417 *
418 * In a way it is "trailing": when scheduling new work this occupancy is measured when the
419 * previous work was rendered. */
421 float occupancy = 1.0f;
423
424 /* Timing of tasks which were performed at the very first render work at 100% of the
425 * resolution. This timing information is used to estimate resolution divider for fats
426 * navigation. */
427 struct {
432
438
439 /* Whether cryptomatte-related work will be scheduled. */
441
442 /* Whether to schedule device load rebalance works.
443 * Rebalancing requires some special treatment for update intervals and such, so if it's known
444 * that the rebalance will be ignored (due to single-device rendering i.e.) is better to fully
445 * ignore rebalancing logic. */
447
448 /* Path tracing work will be scheduled for samples from within
449 * [sample_offset_, sample_offset_ + num_samples_ - 1] range, inclusively. */
452
453 /* Limit in seconds for how long path tracing is allowed to happen.
454 * Zero means no limit is applied. */
455 double time_limit_ = 0.0;
456
457 /* Headless rendering without interface. */
459
460 /* Background (offline) rendering. */
462
463 /* Pixel size is used to force lower resolution render for final pass. Useful for retina or other
464 * types of hi-dpi displays. */
465 int pixel_size_ = 1;
466
468
471
473
474 /* Progressively lower adaptive sampling threshold level, keeping the image at a uniform noise
475 * level. */
477
478 /* Default value for the resolution divider which will be used when there is no render time
479 * information available yet.
480 * It is also what defines the upper limit of the automatically calculated resolution divider. */
482
483 /* Initial resolution divider which will be used on render scheduler reset. */
485
486 /* Calculate smallest resolution divider which will bring down actual rendering time below the
487 * desired one. This call assumes linear dependency of render time from number of pixels
488 * (quadratic dependency from the resolution divider): resolution divider of 2 brings render time
489 * down by a factor of 4. */
490 int calculate_resolution_divider_for_time(const double desired_time, const double actual_time);
491
492 /* If the number of samples per rendering progression should be limited because of path guiding
493 * being activated or is still inside its training phase */
495};
496
498 const int height,
499 const int resolution);
500
501int calculate_resolution_for_divider(const int width,
502 const int height,
503 const int resolution_divider);
504
void reset()
clear internal cached data and reset random seed
void add_average(const double time, const int num_measurements=1)
void add_wall(const double time)
AdaptiveSampling adaptive_sampling_
DenoiseParams denoiser_params_
void set_time_limit(const double time_limit)
void update_state_for_render_work(const RenderWork &render_work)
void report_path_trace_occupancy(const RenderWork &render_work, const float occupancy)
double guess_display_update_interval_in_seconds_for_num_samples(const int num_rendered_samples) const
float work_adaptive_threshold() const
int calculate_num_samples_per_update() const
int get_rendered_sample() const
void report_adaptive_filter_time(const RenderWork &render_work, const double time, bool is_cancelled)
bool work_need_update_display(const bool denoiser_delayed)
BufferParams buffer_params_
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
int get_num_rendered_samples() const
string full_report() const
bool need_schedule_rebalance_works_
bool is_denoise_active_during_update() const
void report_denoise_time(const RenderWork &render_work, const double time)
bool set_postprocess_render_work(RenderWork *render_work)
struct RenderScheduler::@307162023347152161146266305120135320017210234154 first_render_time_
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)
int calculate_resolution_divider_for_time(const double desired_time, const double actual_time)
bool is_adaptive_sampling_used() const
double last_display_update_time
void set_denoiser_params(const DenoiseParams &params)
bool render_work_reschedule_on_idle(RenderWork &render_work)
int get_num_samples() const
TimeWithAverage adaptive_filter_time_
void report_display_update_time(const RenderWork &render_work, const double time)
TimeWithAverage rebalance_time_
void set_sample_params(const int num_samples, const bool use_sample_subset, const int sample_subset_offset, const int sample_subset_length)
int get_sample_offset() const
int default_start_resolution_divider_
bool is_denoiser_gpu_used() const
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 report_path_trace_time(const RenderWork &render_work, const double time, bool is_cancelled)
void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling)
int get_num_samples_during_navigation(const int resolution_divider) const
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_
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
void report_work_begin(const RenderWork &render_work)
TimeWithAverage denoise_time_
void set_need_schedule_cryptomatte(bool need_schedule_cryptomatte)
void report_rebalance_time(const RenderWork &render_work, const double time, bool balance_changed)
void set_limit_samples_per_update(const int limit_samples)
struct RenderScheduler::@103162170344336044223356376364272314126075132375 state_
RenderWork get_render_work()
RenderScheduler(TileManager &tile_manager, const SessionParams &params)
bool is_background() const
struct RenderWork::@234243005336240312017300353332335015376006011032 tile
bool use_denoised_result
bool init_render_buffers
struct RenderWork::@321020210137044117222023120321050035111302276245 adaptive_sampling
struct RenderWork::@077136342205336051112102203105130245030065023152 cryptomatte
struct RenderWork::@020211146253350223233167140037223126305301153241 display
struct RenderWork::@070014147123337267036007142117171267326104033173 path_trace
struct RenderWork::@046146066063235207264076124106046251201154246321 full
#define CCL_NAMESPACE_END
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
const ccl_global KernelWorkTile * tile
int calculate_resolution_for_divider(const int width, const int height, const int resolution_divider)
int calculate_resolution_divider_for_resolution(const int width, const int height, const int resolution)