diff options
Diffstat (limited to 'intern/cycles/integrator/path_trace_work_cpu.cpp')
-rw-r--r-- | intern/cycles/integrator/path_trace_work_cpu.cpp | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp index 518ef3185f9..188ec28cf65 100644 --- a/intern/cycles/integrator/path_trace_work_cpu.cpp +++ b/intern/cycles/integrator/path_trace_work_cpu.cpp @@ -6,6 +6,7 @@ #include "device/cpu/kernel.h" #include "device/device.h" +#include "kernel/film/write.h" #include "kernel/integrator/path_state.h" #include "integrator/pass_accessor_cpu.h" @@ -145,6 +146,13 @@ void PathTraceWorkCPU::render_samples_full_pipeline(KernelGlobalsCPU *kernel_glo kernels_.integrator_megakernel(kernel_globals, state, render_buffer); +#ifdef WITH_PATH_GUIDING + if (kernel_globals->data.integrator.train_guiding) { + /* Push the generated sample data to the global sample data storage. */ + guiding_push_sample_data_to_global_storage(kernel_globals, state, render_buffer); + } +#endif + if (shadow_catcher_state) { kernels_.integrator_megakernel(kernel_globals, shadow_catcher_state, render_buffer); } @@ -276,4 +284,106 @@ void PathTraceWorkCPU::cryptomatte_postproces() }); } +#ifdef WITH_PATH_GUIDING +/* NOTE: It seems that this is called before every rendering iteration/progression and not once per + * rendering. May be we find a way to call it only once per rendering. */ +void PathTraceWorkCPU::guiding_init_kernel_globals(void *guiding_field, + void *sample_data_storage, + const bool train) +{ + /* Linking the global guiding structures (e.g., Field and SampleStorage) to the per-thread + * kernel globals. */ + for (int thread_index = 0; thread_index < kernel_thread_globals_.size(); thread_index++) { + CPUKernelThreadGlobals &kg = kernel_thread_globals_[thread_index]; + openpgl::cpp::Field *field = (openpgl::cpp::Field *)guiding_field; + + /* Allocate sampling distributions. */ + kg.opgl_guiding_field = field; + +# if PATH_GUIDING_LEVEL >= 4 + if (kg.opgl_surface_sampling_distribution) { + delete kg.opgl_surface_sampling_distribution; + kg.opgl_surface_sampling_distribution = nullptr; + } + if (kg.opgl_volume_sampling_distribution) { + delete kg.opgl_volume_sampling_distribution; + kg.opgl_volume_sampling_distribution = nullptr; + } + + if (field) { + kg.opgl_surface_sampling_distribution = new openpgl::cpp::SurfaceSamplingDistribution(field); + kg.opgl_volume_sampling_distribution = new openpgl::cpp::VolumeSamplingDistribution(field); + } +# endif + + /* Reserve storage for training. */ + kg.data.integrator.train_guiding = train; + kg.opgl_sample_data_storage = (openpgl::cpp::SampleStorage *)sample_data_storage; + + if (train) { + kg.opgl_path_segment_storage->Reserve(kg.data.integrator.transparent_max_bounce + + kg.data.integrator.max_bounce + 3); + kg.opgl_path_segment_storage->Clear(); + } + } +} + +void PathTraceWorkCPU::guiding_push_sample_data_to_global_storage( + KernelGlobalsCPU *kg, IntegratorStateCPU *state, ccl_global float *ccl_restrict render_buffer) +{ +# ifdef WITH_CYCLES_DEBUG + if (VLOG_WORK_IS_ON) { + /* Check if the generated path segments contain valid values. */ + const bool validSegments = kg->opgl_path_segment_storage->ValidateSegments(); + if (!validSegments) { + VLOG_WORK << "Guiding: invalid path segments!"; + } + } + + /* Write debug render pass to validate it matches combined pass. */ + pgl_vec3f pgl_final_color = kg->opgl_path_segment_storage->CalculatePixelEstimate(false); + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + ccl_global float *buffer = render_buffer + render_buffer_offset; + float3 final_color = make_float3(pgl_final_color.x, pgl_final_color.y, pgl_final_color.z); + if (kernel_data.film.pass_guiding_color != PASS_UNUSED) { + film_write_pass_float3(buffer + kernel_data.film.pass_guiding_color, final_color); + } +# else + (void)state; + (void)render_buffer; +# endif + + /* Convert the path segment representation of the random walk into radiance samples. */ +# if PATH_GUIDING_LEVEL >= 2 + const bool use_direct_light = kernel_data.integrator.use_guiding_direct_light; + const bool use_mis_weights = kernel_data.integrator.use_guiding_mis_weights; + kg->opgl_path_segment_storage->PrepareSamples( + false, nullptr, use_mis_weights, use_direct_light, false); +# endif + +# ifdef WITH_CYCLES_DEBUG + /* Check if the training/radiance samples generated py the path segment storage are valid.*/ + if (VLOG_WORK_IS_ON) { + const bool validSamples = kg->opgl_path_segment_storage->ValidateSamples(); + if (!validSamples) { + VLOG_WORK + << "Guiding: path segment storage generated/contains invalid radiance/training samples!"; + } + } +# endif + +# if PATH_GUIDING_LEVEL >= 3 + /* Push radiance samples from current random walk/path to the global sample storage. */ + size_t num_samples = 0; + const openpgl::cpp::SampleData *samples = kg->opgl_path_segment_storage->GetSamples(num_samples); + kg->opgl_sample_data_storage->AddSamples(samples, num_samples); +# endif + + /* Clear storage for the current path, to be ready for the next path. */ + kg->opgl_path_segment_storage->Clear(); +} +#endif + CCL_NAMESPACE_END |