32 denoise_device_(denoise_device),
34 device_scene_(device_scene),
35 render_scheduler_(render_scheduler),
36 tile_manager_(tile_manager)
52 path_trace_device, film, device_scene, &
render_cancel_.is_requested);
75 display_->graphics_interop_activate();
81 display_->graphics_interop_deactivate();
89 path_trace_work->alloc_work_memory();
119 const bool reset_rendering)
132 display_->reset(big_tile_params, reset_rendering);
148 path_trace_work->get_render_buffers()->reset(empty_params);
211 if (use_guiding && train_guiding) {
241 path_trace_work->init_execution();
248template<
typename Callback>
255 const int num_works = path_trace_works.size();
259 for (
int i = 0; i < num_works; ++i) {
260 const double weight = work_balance_infos[i].weight;
261 const int slice_window_full_y = buffer_params.
full_y + buffer_params.
window_y + current_y;
262 const int slice_window_height =
max(lround(window_height * weight), 1);
266 const int remaining_window_height =
max(0, window_height - current_y);
270 slice_params.
full_y =
max(slice_window_full_y - overscan, buffer_params.
full_y);
271 slice_params.
window_y = slice_window_full_y - slice_params.
full_y;
273 if (i < num_works - 1) {
274 slice_params.
window_height =
min(slice_window_height, remaining_window_height);
286 callback(path_trace_works[i].get(), slice_params);
317 scaled_params.
full_x =
params.full_x / resolution_divider;
318 scaled_params.
full_y =
params.full_y / resolution_divider;
324 return scaled_params;
339 scaled_big_tile_params,
343 scaled_full_params, scaled_big_tile_params,
params);
346 render_state_.effective_big_tile_params = scaled_big_tile_params;
371 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
372 path_trace_work->zero_render_buffers();
388 const double start_time =
time_dt();
394 parallel_for(0, num_works, [&](
int i) {
395 const double work_start_time =
time_dt();
409 DCHECK(isfinite(statistics.occupancy));
411 const double work_time =
time_dt() - work_start_time;
415 VLOG_INFO <<
"Rendered " << num_samples <<
" samples in " << work_time <<
" seconds ("
416 << work_time / num_samples
417 <<
" seconds per sample), occupancy: " << statistics.occupancy;
420 float occupancy_accum = 0.0f;
422 occupancy_accum += balance_info.occupancy;
424 const float occupancy = occupancy_accum / num_works;
437 bool did_reschedule_on_idle =
false;
440 VLOG_WORK <<
"Will filter adaptive stopping buffer, threshold "
443 VLOG_WORK <<
"Will re-calculate convergency flag for currently converged pixels.";
446 const double start_time =
time_dt();
448 uint num_active_pixels = 0;
449 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
450 const uint num_active_pixels_in_work =
451 path_trace_work->adaptive_sampling_converge_filter_count_active(
453 if (num_active_pixels_in_work) {
461 if (num_active_pixels == 0) {
466 VLOG_WORK <<
"Continuing with lower threshold.";
468 else if (did_reschedule_on_idle) {
471 else if (num_active_pixels < 128 * 128) {
478 VLOG_WORK <<
"Rescheduling is not possible: final threshold is reached.";
481 VLOG_WORK <<
"Rescheduling lower threshold.";
482 did_reschedule_on_idle =
true;
497 Device *effective_denoise_device;
502 bool need_to_recreate_denoiser =
false;
507 old_denoiser_params.
use_gpu ==
false;
508 const bool requested_gpu_denoising = effective_denoise_params.
type ==
DENOISER_OPTIX ||
509 (effective_denoise_params.
type ==
511 effective_denoise_params.
use_gpu ==
true);
512 if (requested_gpu_denoising && is_cpu_denoising &&
521 const bool is_same_denoising_device_type = old_denoiser_params.
use_gpu ==
522 effective_denoise_params.
use_gpu;
525 if (old_denoiser_params.
type == effective_denoise_params.
type &&
528 denoiser_->set_params(effective_denoise_params);
531 need_to_recreate_denoiser =
true;
536 need_to_recreate_denoiser =
true;
539 if (need_to_recreate_denoiser) {
541 effective_denoise_device, cpu_fallback_device, effective_denoise_params);
566 VLOG_WORK <<
"Perform cryptomatte work.";
568 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
569 path_trace_work->cryptomatte_postproces();
586 const double start_time =
time_dt();
589 bool allow_inplace_modification =
false;
606 allow_inplace_modification =
true;
617 allow_inplace_modification))
638 display_ = make_unique<PathTraceDisplay>(std::move(driver));
682 VLOG_WORK <<
"Skipping PathTraceDisplay update due to 0 size of the render buffer.";
686 const double start_time =
time_dt();
689 VLOG_WORK <<
"Invoke buffer update callback.";
696 VLOG_WORK <<
"Perform copy to GPUDisplay work.";
698 const int texture_width =
render_state_.effective_big_tile_params.window_width;
699 const int texture_height =
render_state_.effective_big_tile_params.window_height;
700 if (!
display_->update_begin(texture_width, texture_height)) {
701 LOG(ERROR) <<
"Error beginning GPUDisplay update.";
718 path_trace_work->copy_to_display(
display_.get(), pass_mode, num_samples);
736 if (num_works == 1) {
737 VLOG_WORK <<
"Ignoring rebalance work due to single device render.";
741 const double start_time =
time_dt();
745 VLOG_WORK <<
"Per-device path tracing time (seconds):";
746 for (
int i = 0; i < num_works; ++i) {
755 VLOG_WORK <<
"Calculated per-device weights for works:";
756 for (
int i = 0; i < num_works; ++i) {
762 if (!did_rebalance) {
763 VLOG_WORK <<
"Balance in path trace works did not change.";
800 if (!has_multiple_tiles) {
801 VLOG_WORK <<
"Write tile result via buffer write callback.";
807 VLOG_WORK <<
"Write tile result to disk.";
818 VLOG_WORK <<
"Handle full-frame render buffer work.";
888 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
889 path_trace_work->copy_render_buffers_from_device();
896 parallel_for_each(
path_trace_works_, [](unique_ptr<PathTraceWork> &path_trace_work) {
897 path_trace_work->copy_render_buffers_to_device();
909 if (num_rendered_samples == 0) {
926 buffers = &big_tile_cpu_buffers;
989 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
993 if (!path_trace_work->copy_render_buffers_from_device()) {
1005 if (
buffers.params.layer.size()) {
1006 result += string(
buffers.params.layer);
1009 if (
buffers.params.view.size()) {
1010 if (!result.empty()) {
1013 result += string(
buffers.params.view);
1021 VLOG_WORK <<
"Processing full frame buffer file " << filename;
1029 const string error_message =
"Error reading tiles from file";
1035 LOG(ERROR) << error_message;
1044 if (denoise_params.
use) {
1059 denoiser_->denoise_buffer(full_frame_buffers.
params, &full_frame_buffers, 0,
false);
1100 bool success =
true;
1102 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
1106 if (!path_trace_work->get_render_tile_pixels(pass_accessor, destination)) {
1117 bool success =
true;
1119 parallel_for_each(
path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
1123 if (!path_trace_work->set_render_tile_pixels(pass_accessor, source)) {
1178 path_trace_work->destroy_gpu_resources(
display_.get());
1224 string full_description = device_info.
description;
1229 full_description +=
" (display)";
1236 full_description +=
" [" + device_info.
id +
"]";
1238 return full_description;
1256 string result =
"\n" + message +
": ";
1257 const string pad(message.length() + 2,
' ');
1264 bool is_first =
true;
1283 for (
auto &&path_trace_work : path_trace_works) {
1284 device_info.
multi_devices.push_back(path_trace_work->get_device()->info);
1301 if (!denoiser_device) {
1310 string result =
"\nFull path tracing report\n";
1326#ifdef WITH_PATH_GUIDING
1327 if (guiding_params_.modified(guiding_params)) {
1328 guiding_params_ = guiding_params;
1330# if !(OPENPGL_VERSION_MAJOR == 0 && OPENPGL_VERSION_MINOR <= 5)
1331# define OPENPGL_USE_FIELD_CONFIG
1334 if (guiding_params_.use) {
1335# ifdef OPENPGL_USE_FIELD_CONFIG
1336 openpgl::cpp::FieldConfig field_config;
1338 PGLFieldArguments field_args;
1340 switch (guiding_params_.type) {
1344# ifdef OPENPGL_USE_FIELD_CONFIG
1346 PGL_SPATIAL_STRUCTURE_TYPE::PGL_SPATIAL_STRUCTURE_KDTREE,
1347 PGL_DIRECTIONAL_DISTRIBUTION_TYPE::PGL_DIRECTIONAL_DISTRIBUTION_PARALLAX_AWARE_VMM,
1350 pglFieldArgumentsSetDefaults(
1352 PGL_SPATIAL_STRUCTURE_TYPE::PGL_SPATIAL_STRUCTURE_KDTREE,
1353 PGL_DIRECTIONAL_DISTRIBUTION_TYPE::PGL_DIRECTIONAL_DISTRIBUTION_PARALLAX_AWARE_VMM);
1359# ifdef OPENPGL_USE_FIELD_CONFIG
1361 PGL_SPATIAL_STRUCTURE_TYPE::PGL_SPATIAL_STRUCTURE_KDTREE,
1362 PGL_DIRECTIONAL_DISTRIBUTION_TYPE::PGL_DIRECTIONAL_DISTRIBUTION_QUADTREE,
1365 pglFieldArgumentsSetDefaults(
1367 PGL_SPATIAL_STRUCTURE_TYPE::PGL_SPATIAL_STRUCTURE_KDTREE,
1368 PGL_DIRECTIONAL_DISTRIBUTION_TYPE::PGL_DIRECTIONAL_DISTRIBUTION_QUADTREE);
1374# ifdef OPENPGL_USE_FIELD_CONFIG
1375 field_config.Init(PGL_SPATIAL_STRUCTURE_TYPE::PGL_SPATIAL_STRUCTURE_KDTREE,
1376 PGL_DIRECTIONAL_DISTRIBUTION_TYPE::PGL_DIRECTIONAL_DISTRIBUTION_VMM,
1379 pglFieldArgumentsSetDefaults(
1381 PGL_SPATIAL_STRUCTURE_TYPE::PGL_SPATIAL_STRUCTURE_KDTREE,
1382 PGL_DIRECTIONAL_DISTRIBUTION_TYPE::PGL_DIRECTIONAL_DISTRIBUTION_VMM);
1387# ifdef OPENPGL_USE_FIELD_CONFIG
1388 field_config.SetSpatialStructureArgMaxDepth(16);
1391 reinterpret_cast<PGLKDTreeArguments *
>(field_args.spatialSturctureArguments)->maxDepth = 16;
1393 openpgl::cpp::Device *guiding_device =
static_cast<openpgl::cpp::Device *
>(
1395 if (guiding_device) {
1396 guiding_sample_data_storage_ = make_unique<openpgl::cpp::SampleStorage>();
1397# ifdef OPENPGL_USE_FIELD_CONFIG
1398 guiding_field_ = make_unique<openpgl::cpp::Field>(guiding_device, field_config);
1400 guiding_field_ = make_unique<openpgl::cpp::Field>(guiding_device, field_args);
1404 guiding_sample_data_storage_ =
nullptr;
1405 guiding_field_ =
nullptr;
1409 guiding_sample_data_storage_ =
nullptr;
1410 guiding_field_ =
nullptr;
1414 if (guiding_field_) {
1415 guiding_field_->Reset();
1419 (void)guiding_params;
1426#ifdef WITH_PATH_GUIDING
1427 const bool train = (guiding_params_.training_samples == 0) ||
1428 (guiding_field_->GetIteration() < guiding_params_.training_samples);
1431 path_trace_work->guiding_init_kernel_globals(
1432 guiding_field_.get(), guiding_sample_data_storage_.get(), train);
1451#ifdef WITH_PATH_GUIDING
1452 VLOG_WORK <<
"Update path guiding structures";
1454 VLOG_DEBUG <<
"Number of surface samples: " << guiding_sample_data_storage_->GetSizeSurface();
1455 VLOG_DEBUG <<
"Number of volume samples: " << guiding_sample_data_storage_->GetSizeVolume();
1457 const size_t num_valid_samples = guiding_sample_data_storage_->GetSizeSurface() +
1458 guiding_sample_data_storage_->GetSizeVolume();
1461 if (num_valid_samples >= 1024) {
1462 guiding_field_->Update(*guiding_sample_data_storage_);
1463 guiding_update_count++;
1465 VLOG_DEBUG <<
"Path guiding field valid: " << guiding_field_->Validate();
1467 guiding_sample_data_storage_->Clear();
ATOMIC_INLINE unsigned int atomic_add_and_fetch_u(unsigned int *p, unsigned int x)
int pad[32 - sizeof(int)]
void reset()
clear internal cached data and reset random seed
int get_pass_offset(PassType type, PassMode mode=PassMode::NOISY) const
void update_offset_stride()
bool modified(const BufferParams &other) const
Device * get_denoiser_device() const
static unique_ptr< Denoiser > create(Device *denoise_device, Device *cpu_fallback_device, const DenoiseParams ¶ms)
const DenoiseParams & get_params() const
vector< DeviceInfo > multi_devices
virtual void foreach_device(const function< void(Device *)> &callback)
virtual void set_error(const string &error)
virtual void * get_guiding_device() const
bool get_render_tile_pixels(const RenderBuffers *render_buffers, const Destination &destination) const
const PassAccessInfo & get_pass_access_info() const
RenderBuffers * get_render_buffers()
void set_effective_buffer_params(const BufferParams &effective_full_params, const BufferParams &effective_big_tile_params, const BufferParams &effective_buffer_params)
virtual void render_samples(RenderStatistics &statistics, int start_sample, int samples_num, int sample_offset)=0
static unique_ptr< PathTraceWork > create(Device *device, Film *film, DeviceScene *device_scene, bool *cancel_requested_flag)
Device * get_device() const
function< void(void)> progress_update_cb
void denoise(const RenderWork &render_work)
int2 get_render_tile_size() const
void finalize_full_buffer_on_disk(const RenderWork &render_work)
struct PathTrace::@1422 render_state_
void process_full_buffer_from_disk(string_view filename)
unique_ptr< Denoiser > denoiser_
void update_effective_work_buffer_params(const RenderWork &render_work)
BufferParams full_params_
void rebalance(const RenderWork &render_work)
bool is_cancel_requested()
void init_render_buffers(const RenderWork &render_work)
void copy_to_render_buffers(RenderBuffers *render_buffers)
void destroy_gpu_resources()
void set_progress(Progress *progress)
vector< unique_ptr< PathTraceWork > > path_trace_works_
void copy_from_render_buffers(RenderBuffers *render_buffers)
void set_denoiser_params(const DenoiseParams ¶ms)
void progress_update_if_needed(const RenderWork &render_work)
void update_display(const RenderWork &render_work)
void progress_set_status(const string &status, const string &substatus="")
void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling)
void set_output_driver(unique_ptr< OutputDriver > driver)
void reset(const BufferParams &full_params, const BufferParams &big_tile_params, bool reset_rendering)
DeviceScene * device_scene_
bool get_render_tile_pixels(const PassAccessor &pass_accessor, const PassAccessor::Destination &destination)
void guiding_update_structures()
void guiding_prepare_structures()
int2 get_render_tile_offset() const
unique_ptr< Device > cpu_device_
void set_guiding_params(const GuidingParams ¶ms, const bool reset)
void tile_buffer_write_to_disk()
void set_display_driver(unique_ptr< DisplayDriver > driver)
void path_trace(RenderWork &render_work)
void render_pipeline(RenderWork render_work)
unique_ptr< OutputDriver > output_driver_
unique_ptr< PathTraceDisplay > display_
vector< WorkBalanceInfo > work_balance_infos_
RenderBuffers * render_buffers
bool copy_render_tile_from_device()
PathTrace(Device *device, Device *denoiser_device, Film *film, DeviceScene *device_scene, RenderScheduler &render_scheduler, TileManager &tile_manager)
bool did_draw_after_reset_
void render_init_kernel_execution()
int2 get_render_size() const
TileManager & tile_manager_
unique_ptr< PathTraceWork > big_tile_denoise_work_
void update_work_buffer_params_if_needed(const RenderWork &render_work)
BufferParams big_tile_params_
void write_tile_buffer(const RenderWork &render_work)
bool set_render_tile_pixels(PassAccessor &pass_accessor, const PassAccessor::Source &source)
void render(const RenderWork &render_work)
string full_report() const
void adaptive_sample(RenderWork &render_work)
const BufferParams & get_render_tile_params() const
int get_num_render_tile_samples() const
struct PathTrace::@1424 full_frame_state_
struct PathTrace::@1423 render_cancel_
RenderScheduler & render_scheduler_
int get_num_samples_in_buffer()
void cryptomatte_postprocess(const RenderWork &render_work)
void update_allocated_work_buffer_params()
void set_cancel(const string &cancel_message_)
void set_status(const string &status_, const string &substatus_="")
void add_samples(uint64_t pixel_samples_, int tile_sample)
void set_error(const string &error_message_)
void reset(const BufferParams ¶ms)
void report_display_update_time(const RenderWork &render_work, double time)
void report_adaptive_filter_time(const RenderWork &render_work, double time, bool is_cancelled)
void set_need_schedule_rebalance(bool need_schedule_rebalance)
int get_num_rendered_samples() const
string full_report() const
void report_rebalance_time(const RenderWork &render_work, double time, bool balance_changed)
void report_denoise_time(const RenderWork &render_work, double time)
void set_denoiser_params(const DenoiseParams ¶ms)
bool render_work_reschedule_on_idle(RenderWork &render_work)
void report_path_trace_time(const RenderWork &render_work, double time, bool is_cancelled)
bool is_denoiser_gpu_used() const
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)
void report_work_begin(const RenderWork &render_work)
void set_need_schedule_cryptomatte(bool need_schedule_cryptomatte)
void set_limit_samples_per_update(const int limit_samples)
struct RenderWork::@1432 full
struct RenderWork::@1430 cryptomatte
struct RenderWork::@1429 adaptive_sampling
struct RenderWork::@1431 tile
struct RenderWork::@1433 display
struct RenderWork::@1428 path_trace
bool has_multiple_tiles() const
bool has_written_tiles() const
const int2 get_size() const
const Tile & get_current_tile() const
bool write_tile(const RenderBuffers &tile_buffers)
bool read_full_buffer_from_disk(string_view filename, RenderBuffers *buffers, DenoiseParams *denoise_params)
void finish_write_tiles()
int get_tile_overscan() const
@ DENOISER_OPENIMAGEDENOISE
DenoiseParams get_effective_denoise_params(Device *denoiser_device, Device *cpu_fallback_device, const DenoiseParams ¶ms, Device *&single_denoiser_device)
DEGForeachIDComponentCallback callback
CCL_NAMESPACE_BEGIN Device * device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless)
void device_cpu_info(vector< DeviceInfo > &devices)
#define CCL_NAMESPACE_END
static const char * to_string(const Interpolation &interp)
ccl_global const KernelWorkTile * tile
@ GUIDING_TYPE_DIRECTIONAL_QUAD_TREE
@ GUIDING_TYPE_PARALLAX_AWARE_VMM
#define VLOG_IS_ON(severity)
#define DCHECK(expression)
static string device_info_list_report(const string &message, const DeviceInfo &device_info)
static void foreach_sliced_buffer_params(const vector< unique_ptr< PathTraceWork > > &path_trace_works, const vector< WorkBalanceInfo > &work_balance_infos, const BufferParams &buffer_params, const int overscan, const Callback &callback)
static string path_trace_devices_report(const vector< unique_ptr< PathTraceWork > > &path_trace_works)
static string full_device_info_description(const DeviceInfo &device_info)
static BufferParams scale_buffer_params(const BufferParams ¶ms, int resolution_divider)
static string get_layer_view_name(const RenderBuffers &buffers)
static const char * device_type_for_description(const DeviceType type)
static string denoiser_device_report(const Denoiser *denoiser)
unsigned __int64 uint64_t
static void thread_capture_fp_settings()
std::unique_lock< std::mutex > thread_scoped_lock
CCL_NAMESPACE_BEGIN double time_dt()
CCL_NAMESPACE_BEGIN void work_balance_do_initial(vector< WorkBalanceInfo > &work_balance_infos)
bool work_balance_do_rebalance(vector< WorkBalanceInfo > &work_balance_infos)