Blender V4.3
denoiser.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 "device/device.h"
8
10#ifdef WITH_OPENIMAGEDENOISE
12#endif
14#include "session/buffers.h"
15
16#include "util/log.h"
18#include "util/progress.h"
19
21
22/* Check whether given device is single (not a MultiDevice). */
23static bool is_single_device(const Device *device)
24{
25 if (device->info.type == DEVICE_MULTI) {
26 /* Assume multi-device is never created with a single sub-device.
27 * If one requests such configuration it should be checked on the session level. */
28 return false;
29 }
30
31 if (!device->info.multi_devices.empty()) {
32 /* Some configurations will use multi_devices, but keep the type of an individual device.
33 * This does simplify checks for homogeneous setups, but here we really need a single device.
34 */
35 return false;
36 }
37
38 return true;
39}
40
41/* Find best suitable device to perform denoiser on. Will iterate over possible sub-devices of
42 * multi-device. */
43static Device *find_best_device(Device *device, const DenoiserType type)
44{
45 Device *best_device = nullptr;
46
47 device->foreach_device([&](Device *sub_device) {
48 if ((sub_device->info.denoisers & type) == 0) {
49 return;
50 }
51
52 if (!best_device) {
53 best_device = sub_device;
54 }
55 else {
56 /* Prefer non-CPU devices over CPU for performance reasons. */
57 if (sub_device->info.type != DEVICE_CPU && best_device->info.type == DEVICE_CPU) {
58 best_device = sub_device;
59 }
60
61 /* Prefer a device that can use graphics interop for faster display update. */
62 if (sub_device->should_use_graphics_interop() && !best_device->should_use_graphics_interop())
63 {
64 best_device = sub_device;
65 }
66
67 /* TODO(sergey): Choose fastest device from available ones. Taking into account performance
68 * of the device and data transfer cost. */
69 }
70 });
71
72 return best_device;
73}
74
75bool use_optix_denoiser(Device *denoiser_device, const DenoiseParams &params)
76{
77#ifdef WITH_OPTIX
78 return (params.type == DENOISER_OPTIX &&
79 OptiXDenoiser::is_device_supported(denoiser_device->info));
80#else
81 (void)denoiser_device;
82 (void)params;
83 return false;
84#endif
85}
86
87bool use_gpu_oidn_denoiser(Device *denoiser_device, const DenoiseParams &params)
88{
89#ifdef WITH_OPENIMAGEDENOISE
90 return (params.type == DENOISER_OPENIMAGEDENOISE && params.use_gpu &&
91 OIDNDenoiserGPU::is_device_supported(denoiser_device->info));
92#else
93 (void)denoiser_device;
94 (void)params;
95 return false;
96#endif
97}
98
100 Device *cpu_fallback_device,
101 const DenoiseParams &params,
102 Device *&single_denoiser_device)
103{
104 DCHECK(params.use);
105
106 DenoiseParams effective_denoise_params = params;
107
108 single_denoiser_device = nullptr;
109 if (is_single_device(denoiser_device)) {
110 /* Simple case: denoising happens on a single device. */
111 single_denoiser_device = denoiser_device;
112 }
113 else {
114 /* Find best device from the ones which are proposed for denoising.
115 * The choice is expected to be between a few GPUs, or between a GPU and a CPU
116 * or between a few GPUs and a CPU. */
117 single_denoiser_device = find_best_device(denoiser_device, params.type);
118 }
119 /* Ensure that we have a device to be used later in the code below. */
120 if (single_denoiser_device == nullptr) {
121 single_denoiser_device = cpu_fallback_device;
122 }
123
124 bool is_cpu_denoiser_device = single_denoiser_device->info.type == DEVICE_CPU;
125 if (is_cpu_denoiser_device == false) {
126 if (use_optix_denoiser(single_denoiser_device, effective_denoise_params) ||
127 use_gpu_oidn_denoiser(single_denoiser_device, effective_denoise_params))
128 {
129 /* Denoising parameters are correct and there is no need to fall back to CPU OIDN. */
130 return effective_denoise_params;
131 }
132 }
133
134 /* Always fallback to OIDN on CPU. */
135 effective_denoise_params.type = DENOISER_OPENIMAGEDENOISE;
136 effective_denoise_params.use_gpu = false;
137
138 return effective_denoise_params;
139}
140
141unique_ptr<Denoiser> Denoiser::create(Device *denoiser_device,
142 Device *cpu_fallback_device,
143 const DenoiseParams &params)
144{
145
146 Device *single_denoiser_device;
147 const DenoiseParams effective_denoiser_params = get_effective_denoise_params(
148 denoiser_device, cpu_fallback_device, params, single_denoiser_device);
149
150 bool is_cpu_denoiser_device = single_denoiser_device->info.type == DEVICE_CPU;
151 if (is_cpu_denoiser_device == false) {
152#ifdef WITH_OPTIX
153 if (use_optix_denoiser(single_denoiser_device, effective_denoiser_params)) {
154 return make_unique<OptiXDenoiser>(single_denoiser_device, effective_denoiser_params);
155 }
156#endif
157
158#ifdef WITH_OPENIMAGEDENOISE
159 /* If available and allowed, then we will use OpenImageDenoise on GPU, otherwise on CPU. */
160 if (use_gpu_oidn_denoiser(single_denoiser_device, effective_denoiser_params)) {
161 return make_unique<OIDNDenoiserGPU>(single_denoiser_device, effective_denoiser_params);
162 }
163#endif
164 }
165
166 /* Used preference CPU when possible, and fallback on CPU fallback device otherwise. */
167 return make_unique<OIDNDenoiser>(is_cpu_denoiser_device ? single_denoiser_device :
168 cpu_fallback_device,
169 effective_denoiser_params);
170}
171
173{
174#ifdef WITH_OPENIMAGEDENOISE
175 if (denoise_device_info.type != DEVICE_CPU &&
176 OIDNDenoiserGPU::is_device_supported(denoise_device_info))
177 {
179 }
180#else
181 (void)denoise_device_info;
182#endif
183
184#ifdef WITH_OPTIX
185 if (OptiXDenoiser::is_device_supported(denoise_device_info)) {
186 return DENOISER_OPTIX;
187 }
188#endif
189
190#ifdef WITH_OPENIMAGEDENOISE
193 }
194#endif
195
196 return DENOISER_NONE;
197}
198
200 : denoiser_device_(denoiser_device), denoise_kernels_are_loaded_(false), params_(params)
201{
203 DCHECK(params.use);
204}
205
207{
209
210 if (params.type == params_.type) {
211 params_ = params;
212 }
213 else {
214 LOG(ERROR) << "Attempt to change denoiser type.";
215 }
216}
217
219{
220 return params_;
221}
222
224{
225 /* If we have successfully loaded kernels once, then there is no need to repeat this again. */
228 }
229
230 if (progress) {
231 progress->set_status("Loading denoising kernels (may take a few minutes the first time)");
232 }
233
234 if (!denoiser_device_) {
235 set_error("No device available to denoise on");
236 return false;
237 }
238
239 /* Only need denoising feature, everything else is unused. */
241 string message = denoiser_device_->error_message();
242 if (message.empty()) {
243 message = "Failed loading denoising kernel, see console for errors";
244 }
245 set_error(message);
246 return false;
247 }
248
249 VLOG_WORK << "Will denoise on " << denoiser_device_->info.description << " ("
250 << denoiser_device_->info.id << ")";
251
253 return true;
254}
255
260
DenoiserType type
Definition denoise.h:61
bool use_gpu
Definition denoise.h:75
void set_error(const string &error)
Definition denoiser.h:114
void set_params(const DenoiseParams &params)
Definition denoiser.cpp:206
static DenoiserType automatic_viewport_denoiser_type(const DeviceInfo &denoise_device_info)
Definition denoiser.cpp:172
DenoiseParams params_
Definition denoiser.h:128
Denoiser(Device *denoiser_device, const DenoiseParams &params)
Definition denoiser.cpp:199
virtual bool load_kernels(Progress *progress)
Definition denoiser.cpp:223
bool denoise_kernels_are_loaded_
Definition denoiser.h:127
Device * get_denoiser_device() const
Definition denoiser.cpp:256
static unique_ptr< Denoiser > create(Device *denoise_device, Device *cpu_fallback_device, const DenoiseParams &params)
Definition denoiser.cpp:141
Device * denoiser_device_
Definition denoiser.h:126
const DenoiseParams & get_params() const
Definition denoiser.cpp:218
vector< DeviceInfo > multi_devices
DenoiserTypeMask denoisers
DeviceType type
string description
virtual const string & error_message()
virtual bool load_kernels(uint)
virtual void foreach_device(const function< void(Device *)> &callback)
DeviceInfo info
virtual bool should_use_graphics_interop()
void set_status(const string &status_, const string &substatus_="")
Definition progress.h:263
DenoiserType
Definition denoise.h:13
@ DENOISER_NONE
Definition denoise.h:18
@ DENOISER_OPTIX
Definition denoise.h:14
@ DENOISER_OPENIMAGEDENOISE
Definition denoise.h:15
bool use_gpu_oidn_denoiser(Device *denoiser_device, const DenoiseParams &params)
Definition denoiser.cpp:87
DenoiseParams get_effective_denoise_params(Device *denoiser_device, Device *cpu_fallback_device, const DenoiseParams &params, Device *&single_denoiser_device)
Definition denoiser.cpp:99
static Device * find_best_device(Device *device, const DenoiserType type)
Definition denoiser.cpp:43
bool use_optix_denoiser(Device *denoiser_device, const DenoiseParams &params)
Definition denoiser.cpp:75
static CCL_NAMESPACE_BEGIN bool is_single_device(const Device *device)
Definition denoiser.cpp:23
bool use_gpu_oidn_denoiser(Device *denoiser_device, const DenoiseParams &params)
Definition denoiser.cpp:87
DenoiseParams get_effective_denoise_params(Device *denoiser_device, Device *cpu_fallback_device, const DenoiseParams &params, Device *&single_denoiser_device)
Definition denoiser.cpp:99
bool use_optix_denoiser(Device *denoiser_device, const DenoiseParams &params)
Definition denoiser.cpp:75
#define CCL_NAMESPACE_END
@ DEVICE_MULTI
@ DEVICE_CPU
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define KERNEL_FEATURE_DENOISING
#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 CCL_NAMESPACE_BEGIN bool openimagedenoise_supported()