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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a vector
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
Denoiser(Device *denoiser_device, const DenoiseParams &params)
Definition denoiser.cpp:199
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]
if(state< num_states)
#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)
ThreadQueue * queue
all scheduled work for the cpu
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: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