7#include "device/cpu/kernel.h"
10#ifdef WITH_CYCLES_DEBUG
40 const int thread_index = tbb::this_task_arena::current_thread_index();
42 DCHECK_LE(thread_index, kernel_thread_globals.size());
44 return &kernel_thread_globals[thread_index];
50 const bool *cancel_requested_flag)
51 :
PathTraceWork(device, film, device_scene, cancel_requested_flag),
64 const int start_sample,
65 const int samples_num,
66 const int sample_offset)
72 if (
device_->profiler.active()) {
74 kernel_globals.start_profiling();
79 local_arena.execute([&]() {
80 parallel_for(
int64_t(0), total_pixels_num, [&](
int64_t work_index) {
104 if (
device_->profiler.active()) {
106 kernel_globals.stop_profiling();
115 const int samples_num)
125 shadow_catcher_state = &integrator_states[1];
140 if (!
kernels_.integrator_init_from_bake(
147 if (!
kernels_.integrator_init_from_camera(
154#if defined(WITH_PATH_GUIDING)
155 if (kernel_globals->
data.integrator.train_guiding) {
156 assert(kernel_globals->opgl_path_segment_storage);
157 assert(kernel_globals->opgl_path_segment_storage->GetNumSegments() == 0);
165 if (shadow_catcher_state) {
166 kernel_globals->
data.integrator.train_guiding =
false;
168 kernel_globals->
data.integrator.train_guiding =
true;
175 if (shadow_catcher_state) {
182 if (render_timer.
lap(time)) {
184 kernel_globals->
data.film.pass_stride;
185 *(buffer + kernel_globals->
data.film.pass_render_time) +=
float(time);
194 const int num_samples)
210 const PassAccessorCPU pass_accessor(pass_access_info, kfilm.exposure, num_samples);
216 local_arena.execute([&]() {
227 return buffers_->copy_from_device();
254 uint num_active_pixels = 0;
259 local_arena.execute([&]() {
260 parallel_for(full_y, full_y + height, [&](
int y) {
263 bool row_converged =
true;
264 uint num_row_pixels_active = 0;
265 for (
int x = 0;
x < width; ++
x) {
266 if (!
kernels_.adaptive_sampling_convergence_check(
269 ++num_row_pixels_active;
270 row_converged =
false;
276 if (!row_converged) {
277 kernels_.adaptive_sampling_filter_x(
283 if (num_active_pixels) {
284 local_arena.execute([&]() {
285 parallel_for(full_x, full_x + width, [&](
int x) {
287 kernels_.adaptive_sampling_filter_y(
288 kernel_globals,
render_buffer,
x, full_y, height, offset, stride);
293 return num_active_pixels;
306 local_arena.execute([&]() {
307 parallel_for(0, height, [&](
int y) {
309 int pixel_index =
y * width;
311 for (
int x = 0;
x < width; ++
x, ++pixel_index) {
331 const blocked_range2d<int> range(min_x, max_x, min_y, max_y);
334 local_arena.execute([&]() {
335 parallel_for(range, [&](
const blocked_range2d<int> r) {
337 for (
int y = r.cols().begin();
y < r.cols().end(); ++
y) {
338 for (
int x = r.rows().begin();
x < r.rows().end(); ++
x) {
348 local_arena.execute([&]() {
349 parallel_for(min_x, max_x, [&](
int x) {
357#if defined(WITH_PATH_GUIDING)
360void PathTraceWorkCPU::guiding_init_kernel_globals(
void *guiding_field,
361 void *sample_data_storage,
368 openpgl::cpp::Field *field = (openpgl::cpp::Field *)guiding_field;
371 kg.opgl_guiding_field = field;
373# if PATH_GUIDING_LEVEL >= 4
374 if (kg.opgl_surface_sampling_distribution) {
375 kg.opgl_surface_sampling_distribution.reset();
377 if (kg.opgl_volume_sampling_distribution) {
378 kg.opgl_volume_sampling_distribution.reset();
382 kg.opgl_surface_sampling_distribution =
383 make_unique<openpgl::cpp::SurfaceSamplingDistribution>(field);
384 kg.opgl_volume_sampling_distribution = make_unique<openpgl::cpp::VolumeSamplingDistribution>(
390 kg.
data.integrator.train_guiding = train;
391 kg.opgl_sample_data_storage = (openpgl::cpp::SampleStorage *)sample_data_storage;
394 kg.opgl_path_segment_storage->Reserve(kg.
data.integrator.transparent_max_bounce +
395 kg.
data.integrator.max_bounce + 3);
396 kg.opgl_path_segment_storage->Clear();
406# ifdef WITH_CYCLES_DEBUG
409 const bool validSegments = kg->opgl_path_segment_storage->ValidateSegments();
410 if (!validSegments) {
411 LOG_DEBUG <<
"Guiding: invalid path segments!";
416 pgl_vec3f pgl_final_color = kg->opgl_path_segment_storage->CalculatePixelEstimate(
false);
418 float3 final_color =
make_float3(pgl_final_color.x, pgl_final_color.y, pgl_final_color.z);
428# if PATH_GUIDING_LEVEL >= 2
429 const bool use_direct_light =
kernel_data.integrator.use_guiding_direct_light;
430 const bool use_mis_weights =
kernel_data.integrator.use_guiding_mis_weights;
431 kg->opgl_path_segment_storage->PrepareSamples(use_mis_weights, use_direct_light,
false);
434# ifdef WITH_CYCLES_DEBUG
437 const bool validSamples = kg->opgl_path_segment_storage->ValidateSamples();
440 <<
"Guiding: path segment storage generated/contains invalid radiance/training samples!";
445# if PATH_GUIDING_LEVEL >= 3
447 size_t num_samples = 0;
448 const openpgl::cpp::SampleData *samples = kg->opgl_path_segment_storage->GetSamples(num_samples);
449 kg->opgl_sample_data_storage->AddSamples(samples, num_samples);
453 kg->opgl_path_segment_storage->Clear();
static constexpr int image_width
static constexpr int image_height
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
unsigned long long int uint64_t
void reset()
clear internal cached data and reset random seed
bool get_render_tile_pixels(const RenderBuffers *render_buffers, const Destination &destination) const
half4 * map_texture_buffer()
void unmap_texture_buffer()
bool copy_render_buffers_to_device() override
vector< ThreadKernelGlobalsCPU > kernel_thread_globals_
void render_samples(RenderStatistics &statistics, const int start_sample, const int samples_num, const int sample_offset) override
void init_execution() override
bool copy_render_buffers_from_device() override
int adaptive_sampling_converge_filter_count_active(const float threshold, bool reset) override
void copy_to_display(PathTraceDisplay *display, PassMode pass_mode, const int num_samples) override
void destroy_gpu_resources(PathTraceDisplay *display) override
void cryptomatte_postproces() override
const CPUKernels & kernels_
void render_samples_full_pipeline(ThreadKernelGlobalsCPU *kernel_globals, const KernelWorkTile &work_tile, const int samples_num)
PathTraceWorkCPU(Device *device, Film *film, DeviceScene *device_scene, const bool *cancel_requested_flag)
bool zero_render_buffers() override
void denoise_volume_guiding_buffers() override
PassAccessor::Destination get_display_destination_template(const PathTraceDisplay *display, const PassMode mode) const
unique_ptr< RenderBuffers > buffers_
PassAccessor::PassAccessInfo get_display_pass_access_info(PassMode pass_mode) const
BufferParams effective_buffer_params_
DeviceScene * device_scene_
PathTraceWork(Device *device, Film *film, DeviceScene *device_scene, const bool *cancel_requested_flag)
bool is_cancel_requested() const
bool lap(uint64_t &delta)
#define CCL_NAMESPACE_END
#define assert(assertion)
VecBase< float, 3 > float3
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
CCL_NAMESPACE_BEGIN ccl_device_inline void path_state_init_queues(IntegratorState state)
static ThreadKernelGlobalsCPU * kernel_thread_globals_get(vector< ThreadKernelGlobalsCPU > &kernel_thread_globals)
static CCL_NAMESPACE_BEGIN tbb::task_arena local_tbb_arena_create(const Device *device)
CCL_NAMESPACE_END KernelData data
ccl_device_inline void film_write_pass_float3(ccl_global float *ccl_restrict buffer, const float3 value)
CCL_NAMESPACE_BEGIN ccl_device_forceinline ccl_global float * film_pass_pixel_render_buffer(KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)