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