Blender V4.3
denoiser_oidn.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
6
7#include <array>
8
9#include "device/device.h"
10#include "device/queue.h"
12#include "session/buffers.h"
13#include "util/array.h"
14#include "util/log.h"
16#include "util/path.h"
17
20
22
24
26 : Denoiser(denoiser_device, params)
27{
29
30#ifndef WITH_OPENIMAGEDENOISE
31 set_error("Failed to denoise, build has no OpenImageDenoise support");
32#else
34 set_error("OpenImageDenoiser is not supported on this CPU: missing SSE 4.1 support");
35 }
36#endif
37}
38
39#ifdef WITH_OPENIMAGEDENOISE
40static bool oidn_progress_monitor_function(void *user_ptr, double /*n*/)
41{
42 OIDNDenoiser *oidn_denoiser = reinterpret_cast<OIDNDenoiser *>(user_ptr);
43 return !oidn_denoiser->is_cancelled();
44}
45
46class OIDNPass {
47 public:
48 OIDNPass() = default;
49
50 OIDNPass(const BufferParams &buffer_params,
51 const char *name,
52 PassType type,
54 : name(name), type(type), mode(mode)
55 {
56 offset = buffer_params.get_pass_offset(type, mode);
57 need_scale = (type == PASS_DENOISING_ALBEDO || type == PASS_DENOISING_NORMAL);
58
59 const PassInfo pass_info = Pass::get_info(type);
60 num_components = pass_info.num_components;
61 use_compositing = pass_info.use_compositing;
62 use_denoising_albedo = pass_info.use_denoising_albedo;
63 }
64
65 inline operator bool() const
66 {
67 return name[0] != '\0';
68 }
69
70 /* Name of an image which will be passed to the OIDN library.
71 * Should be one of the following: color, albedo, normal, output.
72 * The albedo and normal images are optional. */
73 const char *name = "";
74
75 PassType type = PASS_NONE;
77 int num_components = -1;
78 bool use_compositing = false;
79 bool use_denoising_albedo = true;
80
81 /* Offset of beginning of this pass in the render buffers. */
82 int offset = -1;
83
84 /* Denotes whether the data is to be scaled down with the number of passes.
85 * Is required for albedo and normal passes. The color pass OIDN will perform auto-exposure, so
86 * scaling is not needed for the color pass unless adaptive sampling is used.
87 *
88 * NOTE: Do not scale the output pass, as that requires to be a pointer in the original buffer.
89 * All the scaling on the output needed for integration with adaptive sampling will happen
90 * outside of generic pass handling. */
91 bool need_scale = false;
92
93 /* The content of the pass has been pre-filtered. */
94 bool is_filtered = false;
95
96 /* For the scaled passes, the data which holds values of scaled pixels. */
97 array<float> scaled_buffer;
98};
99
100class OIDNDenoiseContext {
101 public:
102 OIDNDenoiseContext(OIDNDenoiser *denoiser,
103 const DenoiseParams &denoise_params,
104 const BufferParams &buffer_params,
105 RenderBuffers *render_buffers,
106 const int num_samples,
107 const bool allow_inplace_modification)
108 : denoiser_(denoiser),
109 denoise_params_(denoise_params),
110 buffer_params_(buffer_params),
111 render_buffers_(render_buffers),
112 num_samples_(num_samples),
113 allow_inplace_modification_(allow_inplace_modification),
114 pass_sample_count_(buffer_params_.get_pass_offset(PASS_SAMPLE_COUNT))
115 {
116 if (denoise_params_.use_pass_albedo) {
117 oidn_albedo_pass_ = OIDNPass(buffer_params_, "albedo", PASS_DENOISING_ALBEDO);
118 }
119
120 if (denoise_params_.use_pass_normal) {
121 oidn_normal_pass_ = OIDNPass(buffer_params_, "normal", PASS_DENOISING_NORMAL);
122 }
123
124 const char *custom_weight_path = getenv("CYCLES_OIDN_CUSTOM_WEIGHTS");
125 if (custom_weight_path) {
126 if (!path_read_binary(custom_weight_path, custom_weights)) {
127 fprintf(stderr, "Cycles: Failed to load custom OIDN weights!");
128 }
129 }
130 }
131
132 bool need_denoising() const
133 {
134 if (buffer_params_.width == 0 && buffer_params_.height == 0) {
135 return false;
136 }
137
138 return true;
139 }
140
141 /* Make the guiding passes available by a sequential denoising of various passes. */
142 void read_guiding_passes()
143 {
144 read_guiding_pass(oidn_albedo_pass_);
145 read_guiding_pass(oidn_normal_pass_);
146 }
147
148 void denoise_pass(const PassType pass_type)
149 {
150 OIDNPass oidn_color_pass(buffer_params_, "color", pass_type);
151 if (oidn_color_pass.offset == PASS_UNUSED) {
152 return;
153 }
154
155 if (oidn_color_pass.use_denoising_albedo) {
156 if (albedo_replaced_with_fake_) {
157 LOG(ERROR) << "Pass which requires albedo is denoised after fake albedo has been set.";
158 return;
159 }
160 }
161
162 OIDNPass oidn_output_pass(buffer_params_, "output", pass_type, PassMode::DENOISED);
163 if (oidn_output_pass.offset == PASS_UNUSED) {
164 LOG(DFATAL) << "Missing denoised pass " << pass_type_as_string(pass_type);
165 return;
166 }
167
168 OIDNPass oidn_color_access_pass = read_input_pass(oidn_color_pass, oidn_output_pass);
169
170 oidn::DeviceRef oidn_device = oidn::newDevice(oidn::DeviceType::CPU);
171 oidn_device.set("setAffinity", false);
172 oidn_device.commit();
173
174 /* Create a filter for denoising a beauty (color) image using prefiltered auxiliary images too.
175 */
176 oidn::FilterRef oidn_filter = oidn_device.newFilter("RT");
177 set_input_pass(oidn_filter, oidn_color_access_pass);
178 set_guiding_passes(oidn_filter, oidn_color_pass);
179 set_output_pass(oidn_filter, oidn_output_pass);
180 oidn_filter.setProgressMonitorFunction(oidn_progress_monitor_function, denoiser_);
181 oidn_filter.set("hdr", true);
182 oidn_filter.set("srgb", false);
183 if (custom_weights.size()) {
184 oidn_filter.setData("weights", custom_weights.data(), custom_weights.size());
185 }
186 set_quality(oidn_filter);
187
188 if (denoise_params_.prefilter == DENOISER_PREFILTER_NONE ||
189 denoise_params_.prefilter == DENOISER_PREFILTER_ACCURATE)
190 {
191 oidn_filter.set("cleanAux", true);
192 }
193 oidn_filter.commit();
194
195 filter_guiding_pass_if_needed(oidn_device, oidn_albedo_pass_);
196 filter_guiding_pass_if_needed(oidn_device, oidn_normal_pass_);
197
198 /* Filter the beauty image. */
199 oidn_filter.execute();
200
201 /* Check for errors. */
202 const char *error_message;
203 const oidn::Error error = oidn_device.getError(error_message);
204 if (error != oidn::Error::None && error != oidn::Error::Cancelled) {
205 denoiser_->set_error("OpenImageDenoise error: " + string(error_message));
206 }
207
208 postprocess_output(oidn_color_pass, oidn_output_pass);
209 }
210
211 protected:
212 void filter_guiding_pass_if_needed(oidn::DeviceRef &oidn_device, OIDNPass &oidn_pass)
213 {
214 if (denoise_params_.prefilter != DENOISER_PREFILTER_ACCURATE || !oidn_pass ||
215 oidn_pass.is_filtered)
216 {
217 return;
218 }
219
220 oidn::FilterRef oidn_filter = oidn_device.newFilter("RT");
221 set_pass(oidn_filter, oidn_pass);
222 set_output_pass(oidn_filter, oidn_pass);
223 set_quality(oidn_filter);
224 oidn_filter.commit();
225 oidn_filter.execute();
226
227 oidn_pass.is_filtered = true;
228 }
229
230 /* Make pixels of a guiding pass available by the denoiser. */
231 void read_guiding_pass(OIDNPass &oidn_pass)
232 {
233 if (!oidn_pass) {
234 return;
235 }
236
237 DCHECK(!oidn_pass.use_compositing);
238
239 if (denoise_params_.prefilter != DENOISER_PREFILTER_ACCURATE &&
240 !is_pass_scale_needed(oidn_pass))
241 {
242 /* Pass data is available as-is from the render buffers. */
243 return;
244 }
245
246 if (allow_inplace_modification_) {
247 scale_pass_in_render_buffers(oidn_pass);
248 return;
249 }
250
251 read_pass_pixels_into_buffer(oidn_pass);
252 }
253
254 /* Special reader of the input pass.
255 * To save memory it will read pixels into the output, and let the denoiser to perform an
256 * in-place operation. */
257 OIDNPass read_input_pass(OIDNPass &oidn_input_pass, const OIDNPass &oidn_output_pass)
258 {
259 const bool use_compositing = oidn_input_pass.use_compositing;
260
261 /* Simple case: no compositing is involved, no scaling is needed.
262 * The pass pixels will be referenced as-is, without extra processing. */
263 if (!use_compositing && !is_pass_scale_needed(oidn_input_pass)) {
264 return oidn_input_pass;
265 }
266
267 float *buffer_data = render_buffers_->buffer.data();
268 float *pass_data = buffer_data + oidn_output_pass.offset;
269
270 PassAccessor::Destination destination(pass_data, 3);
271 destination.pixel_stride = buffer_params_.pass_stride;
272
273 read_pass_pixels(oidn_input_pass, destination);
274
275 OIDNPass oidn_input_pass_at_output = oidn_input_pass;
276 oidn_input_pass_at_output.offset = oidn_output_pass.offset;
277
278 return oidn_input_pass_at_output;
279 }
280
281 /* Read pass pixels using PassAccessor into the given destination. */
282 void read_pass_pixels(const OIDNPass &oidn_pass, const PassAccessor::Destination &destination)
283 {
284 PassAccessor::PassAccessInfo pass_access_info;
285 pass_access_info.type = oidn_pass.type;
286 pass_access_info.mode = oidn_pass.mode;
287 pass_access_info.offset = oidn_pass.offset;
288
289 /* Denoiser operates on passes which are used to calculate the approximation, and is never used
290 * on the approximation. The latter is not even possible because OIDN does not support
291 * denoising of semi-transparent pixels. */
292 pass_access_info.use_approximate_shadow_catcher = false;
293 pass_access_info.use_approximate_shadow_catcher_background = false;
294 pass_access_info.show_active_pixels = false;
295
296 /* OIDN will perform an auto-exposure, so it is not required to know exact exposure configured
297 * by users. What is important is to use same exposure for read and write access of the pass
298 * pixels. */
299 const PassAccessorCPU pass_accessor(pass_access_info, 1.0f, num_samples_);
300
301 BufferParams buffer_params = buffer_params_;
302 buffer_params.window_x = 0;
303 buffer_params.window_y = 0;
304 buffer_params.window_width = buffer_params.width;
305 buffer_params.window_height = buffer_params.height;
306
307 pass_accessor.get_render_tile_pixels(render_buffers_, buffer_params, destination);
308 }
309
310 /* Read pass pixels using PassAccessor into a temporary buffer which is owned by the pass.. */
311 void read_pass_pixels_into_buffer(OIDNPass &oidn_pass)
312 {
313 VLOG_WORK << "Allocating temporary buffer for pass " << oidn_pass.name << " ("
314 << pass_type_as_string(oidn_pass.type) << ")";
315
316 const int64_t width = buffer_params_.width;
317 const int64_t height = buffer_params_.height;
318
319 array<float> &scaled_buffer = oidn_pass.scaled_buffer;
320 scaled_buffer.resize(width * height * 3);
321
322 const PassAccessor::Destination destination(scaled_buffer.data(), 3);
323
324 read_pass_pixels(oidn_pass, destination);
325 }
326
327 /* Set OIDN image to reference pixels from the given render buffer pass.
328 * No transform to the pixels is done, no additional memory is used. */
329 void set_pass_referenced(oidn::FilterRef &oidn_filter,
330 const char *name,
331 const OIDNPass &oidn_pass)
332 {
333 const int64_t x = buffer_params_.full_x;
334 const int64_t y = buffer_params_.full_y;
335 const int64_t width = buffer_params_.width;
336 const int64_t height = buffer_params_.height;
337 const int64_t offset = buffer_params_.offset;
338 const int64_t stride = buffer_params_.stride;
339 const int64_t pass_stride = buffer_params_.pass_stride;
340
341 const int64_t pixel_index = offset + x + y * stride;
342 const int64_t buffer_offset = pixel_index * pass_stride;
343
344 float *buffer_data = render_buffers_->buffer.data();
345
346 oidn_filter.setImage(name,
347 buffer_data + buffer_offset + oidn_pass.offset,
348 oidn::Format::Float3,
349 width,
350 height,
351 0,
352 pass_stride * sizeof(float),
353 stride * pass_stride * sizeof(float));
354 }
355
356 void set_pass_from_buffer(oidn::FilterRef &oidn_filter, const char *name, OIDNPass &oidn_pass)
357 {
358 const int64_t width = buffer_params_.width;
359 const int64_t height = buffer_params_.height;
360
361 oidn_filter.setImage(
362 name, oidn_pass.scaled_buffer.data(), oidn::Format::Float3, width, height, 0, 0, 0);
363 }
364
365 void set_pass(oidn::FilterRef &oidn_filter, OIDNPass &oidn_pass)
366 {
367 set_pass(oidn_filter, oidn_pass.name, oidn_pass);
368 }
369 void set_pass(oidn::FilterRef &oidn_filter, const char *name, OIDNPass &oidn_pass)
370 {
371 if (oidn_pass.scaled_buffer.empty()) {
372 set_pass_referenced(oidn_filter, name, oidn_pass);
373 }
374 else {
375 set_pass_from_buffer(oidn_filter, name, oidn_pass);
376 }
377 }
378
379 void set_input_pass(oidn::FilterRef &oidn_filter, OIDNPass &oidn_pass)
380 {
381 set_pass_referenced(oidn_filter, oidn_pass.name, oidn_pass);
382 }
383
384 void set_guiding_passes(oidn::FilterRef &oidn_filter, OIDNPass &oidn_pass)
385 {
386 if (oidn_albedo_pass_) {
387 if (oidn_pass.use_denoising_albedo) {
388 set_pass(oidn_filter, oidn_albedo_pass_);
389 }
390 else {
391 /* NOTE: OpenImageDenoise library implicitly expects albedo pass when normal pass has been
392 * provided. */
393 set_fake_albedo_pass(oidn_filter);
394 }
395 }
396
397 if (oidn_normal_pass_) {
398 set_pass(oidn_filter, oidn_normal_pass_);
399 }
400 }
401
402 void set_fake_albedo_pass(oidn::FilterRef &oidn_filter)
403 {
404 const int64_t width = buffer_params_.width;
405 const int64_t height = buffer_params_.height;
406
407 if (!albedo_replaced_with_fake_) {
408 const int64_t num_pixel_components = width * height * 3;
409 oidn_albedo_pass_.scaled_buffer.resize(num_pixel_components);
410
411 for (int i = 0; i < num_pixel_components; ++i) {
412 oidn_albedo_pass_.scaled_buffer[i] = 0.5f;
413 }
414
415 albedo_replaced_with_fake_ = true;
416 }
417
418 set_pass(oidn_filter, oidn_albedo_pass_);
419 }
420
421 void set_output_pass(oidn::FilterRef &oidn_filter, OIDNPass &oidn_pass)
422 {
423 set_pass(oidn_filter, "output", oidn_pass);
424 }
425
426 void set_quality(oidn::FilterRef &oidn_filter)
427 {
428# if OIDN_VERSION_MAJOR >= 2
429 switch (denoise_params_.quality) {
431# if OIDN_VERSION >= 20300
432 oidn_filter.set("quality", OIDN_QUALITY_FAST);
433 break;
434# endif
436 oidn_filter.set("quality", OIDN_QUALITY_BALANCED);
437 break;
439 default:
440 oidn_filter.set("quality", OIDN_QUALITY_HIGH);
441 }
442# endif
443 }
444
445 /* Scale output pass to match adaptive sampling per-pixel scale, as well as bring alpha channel
446 * back. */
447 void postprocess_output(const OIDNPass &oidn_input_pass, const OIDNPass &oidn_output_pass)
448 {
449 kernel_assert(oidn_input_pass.num_components == oidn_output_pass.num_components);
450
451 const int64_t x = buffer_params_.full_x;
452 const int64_t y = buffer_params_.full_y;
453 const int64_t width = buffer_params_.width;
454 const int64_t height = buffer_params_.height;
455 const int64_t offset = buffer_params_.offset;
456 const int64_t stride = buffer_params_.stride;
457 const int64_t pass_stride = buffer_params_.pass_stride;
458 const int64_t row_stride = stride * pass_stride;
459
460 const int64_t pixel_offset = offset + x + y * stride;
461 const int64_t buffer_offset = (pixel_offset * pass_stride);
462
463 float *buffer_data = render_buffers_->buffer.data();
464
465 const bool has_pass_sample_count = (pass_sample_count_ != PASS_UNUSED);
466 const bool need_scale = has_pass_sample_count || oidn_input_pass.use_compositing;
467
468 for (int y = 0; y < height; ++y) {
469 float *buffer_row = buffer_data + buffer_offset + y * row_stride;
470 for (int x = 0; x < width; ++x) {
471 float *buffer_pixel = buffer_row + x * pass_stride;
472 float *denoised_pixel = buffer_pixel + oidn_output_pass.offset;
473
474 if (need_scale) {
475 const float pixel_scale = has_pass_sample_count ?
476 __float_as_uint(buffer_pixel[pass_sample_count_]) :
477 num_samples_;
478
479 denoised_pixel[0] = denoised_pixel[0] * pixel_scale;
480 denoised_pixel[1] = denoised_pixel[1] * pixel_scale;
481 denoised_pixel[2] = denoised_pixel[2] * pixel_scale;
482 }
483
484 if (oidn_output_pass.num_components == 3) {
485 /* Pass without alpha channel. */
486 }
487 else if (!oidn_input_pass.use_compositing) {
488 /* Currently compositing passes are either 3-component (derived by dividing light passes)
489 * or do not have transparency (shadow catcher). Implicitly rely on this logic, as it
490 * simplifies logic and avoids extra memory allocation. */
491 const float *noisy_pixel = buffer_pixel + oidn_input_pass.offset;
492 denoised_pixel[3] = noisy_pixel[3];
493 }
494 else {
495 /* Assigning to zero since this is a default alpha value for 3-component passes, and it
496 * is an opaque pixel for 4 component passes. */
497 denoised_pixel[3] = 0;
498 }
499 }
500 }
501 }
502
503 bool is_pass_scale_needed(OIDNPass &oidn_pass) const
504 {
505 if (pass_sample_count_ != PASS_UNUSED) {
506 /* With adaptive sampling pixels will have different number of samples in them, so need to
507 * always scale the pass to make pixels uniformly sampled. */
508 return true;
509 }
510
511 if (!oidn_pass.need_scale) {
512 return false;
513 }
514
515 if (num_samples_ == 1) {
516 /* If the avoid scaling if there is only one sample, to save up time (so we don't divide
517 * buffer by 1). */
518 return false;
519 }
520
521 return true;
522 }
523
524 void scale_pass_in_render_buffers(OIDNPass &oidn_pass)
525 {
526 const int64_t x = buffer_params_.full_x;
527 const int64_t y = buffer_params_.full_y;
528 const int64_t width = buffer_params_.width;
529 const int64_t height = buffer_params_.height;
530 const int64_t offset = buffer_params_.offset;
531 const int64_t stride = buffer_params_.stride;
532 const int64_t pass_stride = buffer_params_.pass_stride;
533 const int64_t row_stride = stride * pass_stride;
534
535 const int64_t pixel_offset = offset + x + y * stride;
536 const int64_t buffer_offset = (pixel_offset * pass_stride);
537
538 float *buffer_data = render_buffers_->buffer.data();
539
540 const bool has_pass_sample_count = (pass_sample_count_ != PASS_UNUSED);
541
542 for (int y = 0; y < height; ++y) {
543 float *buffer_row = buffer_data + buffer_offset + y * row_stride;
544 for (int x = 0; x < width; ++x) {
545 float *buffer_pixel = buffer_row + x * pass_stride;
546 float *pass_pixel = buffer_pixel + oidn_pass.offset;
547
548 const float pixel_scale = 1.0f / (has_pass_sample_count ?
549 __float_as_uint(buffer_pixel[pass_sample_count_]) :
550 num_samples_);
551
552 pass_pixel[0] = pass_pixel[0] * pixel_scale;
553 pass_pixel[1] = pass_pixel[1] * pixel_scale;
554 pass_pixel[2] = pass_pixel[2] * pixel_scale;
555 }
556 }
557 }
558
559 OIDNDenoiser *denoiser_ = nullptr;
560
561 const DenoiseParams &denoise_params_;
562 const BufferParams &buffer_params_;
563 RenderBuffers *render_buffers_ = nullptr;
564 int num_samples_ = 0;
565 bool allow_inplace_modification_ = false;
566 int pass_sample_count_ = PASS_UNUSED;
567
568 vector<uint8_t> custom_weights;
569
570 /* Optional albedo and normal passes, reused by denoising of different pass types. */
571 OIDNPass oidn_albedo_pass_;
572 OIDNPass oidn_normal_pass_;
573
574 /* For passes which don't need albedo channel for denoising we replace the actual albedo with
575 * the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
576 * the fake values and denoising of passes which do need albedo can no longer happen. */
577 bool albedo_replaced_with_fake_ = false;
578};
579
580static unique_ptr<DeviceQueue> create_device_queue(const RenderBuffers *render_buffers)
581{
582 Device *device = render_buffers->buffer.device;
583 if (device->info.has_gpu_queue) {
584 return device->gpu_queue_create();
585 }
586 return nullptr;
587}
588
589static void copy_render_buffers_from_device(unique_ptr<DeviceQueue> &queue,
590 RenderBuffers *render_buffers)
591{
592 if (queue) {
593 queue->copy_from_device(render_buffers->buffer);
594 queue->synchronize();
595 }
596 else {
597 render_buffers->copy_from_device();
598 }
599}
600
601static void copy_render_buffers_to_device(unique_ptr<DeviceQueue> &queue,
602 RenderBuffers *render_buffers)
603{
604 if (queue) {
605 queue->copy_to_device(render_buffers->buffer);
606 queue->synchronize();
607 }
608 else {
609 render_buffers->copy_to_device();
610 }
611}
612
613#endif
614
616 RenderBuffers *render_buffers,
617 const int num_samples,
618 bool allow_inplace_modification)
619{
621 << "OpenImageDenoise is not supported on this platform or build.";
622
623#ifdef WITH_OPENIMAGEDENOISE
625
626 /* Make sure the host-side data is available for denoising. */
627 unique_ptr<DeviceQueue> queue = create_device_queue(render_buffers);
628 copy_render_buffers_from_device(queue, render_buffers);
629
630 OIDNDenoiseContext context(
631 this, params_, buffer_params, render_buffers, num_samples, allow_inplace_modification);
632
633 if (context.need_denoising()) {
634 context.read_guiding_passes();
635
636 const std::array<PassType, 3> passes = {
637 {/* Passes which will use real albedo when it is available. */
640
641 /* Passes which do not need albedo and hence if real is present it needs to become fake.
642 */
644
645 for (const PassType pass_type : passes) {
646 context.denoise_pass(pass_type);
647 if (is_cancelled()) {
648 return false;
649 }
650 }
651
652 /* TODO: It may be possible to avoid this copy, but we have to ensure that when other code
653 * copies data from the device it doesn't overwrite the denoiser buffers. */
654 copy_render_buffers_to_device(queue, render_buffers);
655 }
656#else
657 (void)buffer_params;
658 (void)render_buffers;
659 (void)num_samples;
660 (void)allow_inplace_modification;
661#endif
662
663 /* This code is not supposed to run when compiled without OIDN support, so can assume if we made
664 * it up here all passes are properly denoised. */
665 return true;
666}
667
672
unsigned int uint
volatile int lock
int get_pass_offset(PassType type, PassMode mode=PassMode::NOISY) const
Definition buffers.cpp:167
int window_y
Definition buffers.h:80
int window_height
Definition buffers.h:82
int window_width
Definition buffers.h:81
NODE_DECLARE int width
Definition buffers.h:72
int window_x
Definition buffers.h:79
void set_error(const string &error)
Definition denoiser.h:114
DenoiseParams params_
Definition denoiser.h:128
bool is_cancelled() const
Definition denoiser.h:106
bool has_gpu_queue
virtual unique_ptr< DeviceQueue > gpu_queue_create()
DeviceInfo info
virtual bool denoise_buffer(const BufferParams &buffer_params, RenderBuffers *render_buffers, const int num_samples, bool allow_inplace_modification) override
OIDNDenoiser(Device *denoiser_device, const DenoiseParams &params)
virtual uint get_device_type_mask() const override
static thread_mutex mutex_
PassInfo get_info() const
Definition pass.cpp:141
device_vector< float > buffer
Definition buffers.h:160
bool copy_from_device()
Definition buffers.cpp:289
void copy_to_device()
Definition buffers.cpp:302
T * resize(size_t newsize)
@ DENOISER_QUALITY_FAST
Definition denoise.h:46
@ DENOISER_QUALITY_BALANCED
Definition denoise.h:45
@ DENOISER_QUALITY_HIGH
Definition denoise.h:44
@ DENOISER_PREFILTER_NONE
Definition denoise.h:30
@ DENOISER_PREFILTER_ACCURATE
Definition denoise.h:38
@ DENOISER_OPENIMAGEDENOISE
Definition denoise.h:15
#define kernel_assert(cond)
#define CCL_NAMESPACE_END
@ DEVICE_MASK_CPU
#define __float_as_uint(x)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define PASS_UNUSED
PassType
@ PASS_SHADOW_CATCHER_MATTE
@ PASS_SHADOW_CATCHER
@ PASS_DENOISING_NORMAL
@ PASS_COMBINED
@ PASS_NONE
@ PASS_SAMPLE_COUNT
@ PASS_DENOISING_ALBEDO
#define DCHECK(expression)
Definition log.h:51
#define DCHECK_EQ(a, b)
Definition log.h:59
#define VLOG_WORK
Definition log.h:75
#define LOG(severity)
Definition log.h:33
static void error(const char *str)
static CCL_NAMESPACE_BEGIN bool openimagedenoise_supported()
CCL_NAMESPACE_BEGIN const char * pass_type_as_string(const PassType type)
Definition pass.cpp:12
PassMode
Definition pass.h:20
bool path_read_binary(const string &path, vector< uint8_t > &binary)
Definition path.cpp:682
__int64 int64_t
Definition stdint.h:89
bool use_compositing
Definition pass.h:38
bool use_denoising_albedo
Definition pass.h:43
int num_components
Definition pass.h:28
std::unique_lock< std::mutex > thread_scoped_lock
Definition thread.h:30
CCL_NAMESPACE_BEGIN typedef std::mutex thread_mutex
Definition thread.h:29