5#if defined(WITH_OPENIMAGEDENOISE)
23# if OIDN_VERSION_MAJOR < 2
24# define oidnSetFilterBool oidnSetFilter1b
25# define oidnSetFilterInt oidnSetFilter1i
26# define oidnExecuteFilterAsync oidnExecuteFilter
31# if OIDN_VERSION < 20300
32static const char *oidn_device_type_to_string(
const OIDNDeviceType type)
35 case OIDN_DEVICE_TYPE_DEFAULT:
37 case OIDN_DEVICE_TYPE_CPU:
41# if OIDN_VERSION_MAJOR >= 2
42 case OIDN_DEVICE_TYPE_SYCL:
44 case OIDN_DEVICE_TYPE_CUDA:
46 case OIDN_DEVICE_TYPE_HIP:
51# if (OIDN_VERSION_MAJOR > 2) || ((OIDN_VERSION_MAJOR == 2) && (OIDN_VERSION_MINOR >= 2))
52 case OIDN_DEVICE_TYPE_METAL:
60bool OIDNDenoiserGPU::is_device_supported(
const DeviceInfo &device)
62# if OIDN_VERSION >= 20300
64 for (
const DeviceInfo &multi_device : device.multi_devices) {
76 for (
const DeviceInfo &multi_device : device.multi_devices) {
77 if (multi_device.type !=
DEVICE_CPU && is_device_supported(multi_device)) {
86 <<
") for OIDN GPU support";
88 int device_type = OIDN_DEVICE_TYPE_DEFAULT;
89 switch (device.
type) {
90# ifdef OIDN_DEVICE_SYCL
92 device_type = OIDN_DEVICE_TYPE_SYCL;
95# ifdef OIDN_DEVICE_HIP
97 device_type = OIDN_DEVICE_TYPE_HIP;
100# ifdef OIDN_DEVICE_CUDA
103 device_type = OIDN_DEVICE_TYPE_CUDA;
106# ifdef OIDN_DEVICE_METAL
108 const int num_devices = oidnGetNumPhysicalDevices();
109 VLOG_DEBUG <<
"Found " << num_devices <<
" OIDN device(s)";
110 for (
int i = 0; i < num_devices; i++) {
111 const int type = oidnGetPhysicalDeviceInt(i,
"type");
112 const char *name = oidnGetPhysicalDeviceString(i,
"name");
113 VLOG_DEBUG <<
"OIDN device " << i <<
": name=\"" << name
114 <<
"\", type=" << oidn_device_type_to_string(OIDNDeviceType(type));
115 if (type == OIDN_DEVICE_TYPE_METAL) {
116 if (device.
id.find(name) != std::string::npos) {
117 VLOG_DEBUG <<
"OIDN device name matches the Cycles device name";
134 const int num_devices = oidnGetNumPhysicalDevices();
135 VLOG_DEBUG <<
"Found " << num_devices <<
" OIDN device(s)";
136 for (
int i = 0; i < num_devices; i++) {
137 const int type = oidnGetPhysicalDeviceInt(i,
"type");
138 const char *name = oidnGetPhysicalDeviceString(i,
"name");
139 VLOG_DEBUG <<
"OIDN device " << i <<
": name=\"" << name
140 <<
"\" type=" << oidn_device_type_to_string(OIDNDeviceType(type));
141 if (type == device_type) {
142 if (oidnGetPhysicalDeviceBool(i,
"pciAddressSupported")) {
143 unsigned int pci_domain = oidnGetPhysicalDeviceInt(i,
"pciDomain");
144 unsigned int pci_bus = oidnGetPhysicalDeviceInt(i,
"pciBus");
145 unsigned int pci_device = oidnGetPhysicalDeviceInt(i,
"pciDevice");
146 string pci_id =
string_printf(
"%04x:%02x:%02x", pci_domain, pci_bus, pci_device);
147 VLOG_INFO <<
"OIDN device PCI-e identifier: " << pci_id;
148 if (device.
id.find(pci_id) != string::npos) {
149 VLOG_DEBUG <<
"OIDN device PCI-e identifier matches the Cycles device ID";
154 VLOG_DEBUG <<
"Device does not support pciAddressSupported";
169OIDNDenoiserGPU::~OIDNDenoiserGPU()
171 release_all_resources();
174bool OIDNDenoiserGPU::denoise_buffer(
const BufferParams &buffer_params,
176 const int num_samples,
177 bool allow_inplace_modification)
180 buffer_params, render_buffers, num_samples, allow_inplace_modification);
183uint OIDNDenoiserGPU::get_device_type_mask()
const
185 uint device_mask = 0;
186# ifdef OIDN_DEVICE_SYCL
189# ifdef OIDN_DEVICE_METAL
192# ifdef OIDN_DEVICE_CUDA
196# ifdef OIDN_DEVICE_HIP
202OIDNFilter OIDNDenoiserGPU::create_filter()
204 const char *error_message =
nullptr;
205 OIDNFilter filter = oidnNewFilter(oidn_device_,
"RT");
206 if (filter ==
nullptr) {
207 OIDNError err = oidnGetDeviceError(oidn_device_, (
const char **)&error_message);
208 if (OIDN_ERROR_NONE != err) {
209 LOG(ERROR) <<
"OIDN error: " << error_message;
210 set_error(error_message);
214# if OIDN_VERSION_MAJOR >= 2
217# if OIDN_VERSION >= 20300
218 oidnSetFilterInt(filter,
"quality", OIDN_QUALITY_FAST);
222 oidnSetFilterInt(filter,
"quality", OIDN_QUALITY_BALANCED);
226 oidnSetFilterInt(filter,
"quality", OIDN_QUALITY_HIGH);
233bool OIDNDenoiserGPU::commit_and_execute_filter(OIDNFilter filter, ExecMode mode)
235 const char *error_message =
nullptr;
236 OIDNError err = OIDN_ERROR_NONE;
239 oidnCommitFilter(filter);
240 if (mode == ExecMode::ASYNC) {
241 oidnExecuteFilterAsync(filter);
244 oidnExecuteFilter(filter);
248 err = oidnGetDeviceError(oidn_device_, (
const char **)&error_message);
249 if (err != OIDN_ERROR_OUT_OF_MEMORY || max_mem_ < 200) {
252 max_mem_ = max_mem_ / 2;
253 oidnSetFilterInt(filter,
"maxMemoryMB", max_mem_);
256 if (err != OIDN_ERROR_NONE) {
257 if (error_message ==
nullptr) {
258 error_message =
"Unspecified OIDN error";
260 LOG(ERROR) <<
"OIDN error: " << error_message;
261 set_error(error_message);
267bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
269 const bool recreate_denoiser = (oidn_device_ ==
nullptr) || (oidn_filter_ ==
nullptr) ||
270 (use_pass_albedo_ != context.use_pass_albedo) ||
271 (use_pass_normal_ != context.use_pass_normal) ||
272 (quality_ != params_.quality);
273 if (!recreate_denoiser) {
278 release_all_resources();
280 switch (denoiser_device_->info.type) {
281# if defined(OIDN_DEVICE_SYCL) && defined(WITH_ONEAPI)
283 oidn_device_ = oidnNewSYCLDevice(
284 (
const sycl::queue *)
reinterpret_cast<OneapiDevice *
>(denoiser_device_)->sycl_queue(),
288# if defined(OIDN_DEVICE_METAL) && defined(WITH_METAL)
290 denoiser_queue_->init_execution();
291 const MTLCommandQueue_id queue = (
const MTLCommandQueue_id)denoiser_queue_->native_queue();
292 oidn_device_ = oidnNewMetalDevice(&queue, 1);
295# if defined(OIDN_DEVICE_CUDA) && defined(WITH_CUDA)
299 cudaStream_t stream =
nullptr;
300 oidn_device_ = oidnNewCUDADevice(&denoiser_device_->info.num, &stream, 1);
304# if defined(OIDN_DEVICE_HIP) && defined(WITH_HIP)
306 hipStream_t stream =
nullptr;
307 oidn_device_ = oidnNewHIPDevice(&denoiser_device_->info.num, &stream, 1);
316 set_error(
"Failed to create OIDN device");
320 if (denoiser_queue_) {
321 denoiser_queue_->init_execution();
324 oidnCommitDevice(oidn_device_);
326 quality_ = params_.quality;
328 oidn_filter_ = create_filter();
329 if (oidn_filter_ ==
nullptr) {
333 oidnSetFilterBool(oidn_filter_,
"hdr",
true);
334 oidnSetFilterBool(oidn_filter_,
"srgb",
false);
336 const char *custom_weight_path = getenv(
"CYCLES_OIDN_CUSTOM_WEIGHTS");
337 if (custom_weight_path) {
339 oidnSetSharedFilterData(
340 oidn_filter_,
"weights", custom_weights.data(), custom_weights.size());
343 fprintf(stderr,
"Cycles: Failed to load custom OIDN weights!");
347 if (context.use_pass_albedo) {
348 albedo_filter_ = create_filter();
349 if (albedo_filter_ ==
nullptr) {
354 if (context.use_pass_normal) {
355 normal_filter_ = create_filter();
356 if (normal_filter_ ==
nullptr) {
362 use_pass_albedo_ = context.use_pass_albedo;
363 use_pass_normal_ = context.use_pass_normal;
366 is_configured_ =
false;
370bool OIDNDenoiserGPU::denoise_configure_if_needed(DenoiseContext &context)
373 const int2 size =
make_int2(context.buffer_params.width, context.buffer_params.height);
375 if (is_configured_ && (configured_size_.x == size.x && configured_size_.y == size.y)) {
379 is_configured_ =
true;
380 configured_size_ =
size;
385bool OIDNDenoiserGPU::denoise_run(
const DenoiseContext &context,
const DenoisePass &pass)
388 const int64_t pass_stride_in_bytes = context.buffer_params.pass_stride *
sizeof(
float);
390 set_filter_pass(oidn_filter_,
392 context.render_buffers->buffer.device_pointer,
394 context.buffer_params.width,
395 context.buffer_params.height,
396 pass.denoised_offset *
sizeof(
float),
397 pass_stride_in_bytes,
398 pass_stride_in_bytes * context.buffer_params.stride);
400 set_filter_pass(oidn_filter_,
402 context.render_buffers->buffer.device_pointer,
404 context.buffer_params.width,
405 context.buffer_params.height,
406 pass.denoised_offset *
sizeof(
float),
407 pass_stride_in_bytes,
408 pass_stride_in_bytes * context.buffer_params.stride);
411 if (context.num_input_passes > 1) {
412 const device_ptr d_guiding_buffer = context.guiding_params.device_pointer;
413 const int64_t pixel_stride_in_bytes = context.guiding_params.pass_stride *
sizeof(
float);
414 const int64_t row_stride_in_bytes = context.guiding_params.stride * pixel_stride_in_bytes;
416 if (context.use_pass_albedo) {
417 set_filter_pass(oidn_filter_,
421 context.buffer_params.width,
422 context.buffer_params.height,
423 context.guiding_params.pass_albedo *
sizeof(
float),
424 pixel_stride_in_bytes,
425 row_stride_in_bytes);
428 set_filter_pass(albedo_filter_,
432 context.buffer_params.width,
433 context.buffer_params.height,
434 context.guiding_params.pass_albedo *
sizeof(
float),
435 pixel_stride_in_bytes,
436 row_stride_in_bytes);
438 set_filter_pass(albedo_filter_,
442 context.buffer_params.width,
443 context.buffer_params.height,
444 context.guiding_params.pass_albedo *
sizeof(
float),
445 pixel_stride_in_bytes,
446 row_stride_in_bytes);
448 if (!commit_and_execute_filter(albedo_filter_, ExecMode::ASYNC)) {
454 if (context.use_pass_normal) {
455 set_filter_pass(oidn_filter_,
459 context.buffer_params.width,
460 context.buffer_params.height,
461 context.guiding_params.pass_normal *
sizeof(
float),
462 pixel_stride_in_bytes,
463 row_stride_in_bytes);
466 set_filter_pass(normal_filter_,
470 context.buffer_params.width,
471 context.buffer_params.height,
472 context.guiding_params.pass_normal *
sizeof(
float),
473 pixel_stride_in_bytes,
474 row_stride_in_bytes);
476 set_filter_pass(normal_filter_,
480 context.buffer_params.width,
481 context.buffer_params.height,
482 context.guiding_params.pass_normal *
sizeof(
float),
483 pixel_stride_in_bytes,
484 row_stride_in_bytes);
486 if (!commit_and_execute_filter(normal_filter_, ExecMode::ASYNC)) {
494 return commit_and_execute_filter(oidn_filter_);
497void OIDNDenoiserGPU::set_filter_pass(OIDNFilter filter,
503 size_t offset_in_bytes,
504 size_t pixel_stride_in_bytes,
505 size_t row_stride_in_bytes)
507# if defined(OIDN_DEVICE_METAL) && defined(WITH_METAL)
509 void *mtl_buffer = denoiser_device_->get_native_buffer(
ptr);
510 OIDNBuffer oidn_buffer = oidnNewSharedBufferFromMetal(oidn_device_, mtl_buffer);
512 oidnSetFilterImage(filter,
519 pixel_stride_in_bytes,
520 row_stride_in_bytes);
522 oidnReleaseBuffer(oidn_buffer);
527 oidnSetSharedFilterImage(filter,
534 pixel_stride_in_bytes,
535 row_stride_in_bytes);
539void OIDNDenoiserGPU::release_all_resources()
541 if (albedo_filter_) {
542 oidnReleaseFilter(albedo_filter_);
543 albedo_filter_ =
nullptr;
545 if (normal_filter_) {
546 oidnReleaseFilter(normal_filter_);
547 normal_filter_ =
nullptr;
550 oidnReleaseFilter(oidn_filter_);
551 oidn_filter_ =
nullptr;
554 oidnReleaseDevice(oidn_device_);
555 oidn_device_ =
nullptr;
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
virtual bool denoise_buffer(const BufferParams &buffer_params, RenderBuffers *render_buffers, const int num_samples, bool allow_inplace_modification) override
DenoiserTypeMask denoisers
@ DENOISER_QUALITY_BALANCED
@ DENOISER_PREFILTER_FAST
@ DENOISER_PREFILTER_ACCURATE
@ DENOISER_OPENIMAGEDENOISE
#define CCL_NAMESPACE_END
draw_view in_light_buf[] float
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
bool path_read_binary(const string &path, vector< uint8_t > &binary)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)