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