Blender  V3.3
COM_DenoiseOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. */
3 
4 #include "COM_DenoiseOperation.h"
5 #include "BLI_system.h"
6 #ifdef WITH_OPENIMAGEDENOISE
7 # include "BLI_threads.h"
8 # include <OpenImageDenoise/oidn.hpp>
9 static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER;
10 #endif
11 
12 namespace blender::compositor {
13 
15 {
16 #ifdef WITH_OPENIMAGEDENOISE
17  /* Always supported through Accelerate framework BNNS on macOS. */
18 # ifdef __APPLE__
19  return true;
20 # else
21  return BLI_cpu_support_sse41();
22 # endif
23 
24 #else
25  return false;
26 #endif
27 }
28 
30  private:
31 #ifdef WITH_OPENIMAGEDENOISE
32  oidn::DeviceRef device_;
33  oidn::FilterRef filter_;
34 #endif
35  bool initialized_ = false;
36 
37  public:
39  {
40  BLI_assert(!initialized_);
41  }
42 
43 #ifdef WITH_OPENIMAGEDENOISE
45  {
46  /* Since it's memory intensive, it's better to run only one instance of OIDN at a time.
47  * OpenImageDenoise is multithreaded internally and should use all available cores
48  * nonetheless. */
49  BLI_mutex_lock(&oidn_lock);
50 
51  device_ = oidn::newDevice();
52  device_.set("setAffinity", false);
53  device_.commit();
54  filter_ = device_.newFilter("RT");
55  initialized_ = true;
56  set_image("output", output);
57  }
58 
60  {
61  BLI_mutex_unlock(&oidn_lock);
62  initialized_ = false;
63  }
64 
65  void set_image(const StringRef name, MemoryBuffer *buffer)
66  {
67  BLI_assert(initialized_);
68  BLI_assert(!buffer->is_a_single_elem());
69  filter_.setImage(name.data(),
70  buffer->get_buffer(),
71  oidn::Format::Float3,
72  buffer->get_width(),
73  buffer->get_height(),
74  0,
75  buffer->get_elem_bytes_len());
76  }
77 
78  template<typename T> void set(const StringRef option_name, T value)
79  {
80  BLI_assert(initialized_);
81  filter_.set(option_name.data(), value);
82  }
83 
84  void execute()
85  {
86  BLI_assert(initialized_);
87  filter_.commit();
88  filter_.execute();
89  }
90 
91 #else
93  {
94  }
95 
97  {
98  }
99 
101  {
102  }
103 
104  template<typename T> void set(const StringRef UNUSED(option_name), T UNUSED(value))
105  {
106  }
107 
108  void execute()
109  {
110  }
111 #endif
112 };
113 
115 {
117  output_rendered_ = false;
118 }
119 
121  rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
122 {
123  if (is_cached()) {
124  return false;
125  }
126 
127  rcti new_input;
128  new_input.xmax = this->get_width();
129  new_input.xmin = 0;
130  new_input.ymax = this->get_height();
131  new_input.ymin = 0;
132  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
133 }
134 
136  const rcti &UNUSED(output_area),
137  rcti &r_input_area)
138 {
139  r_input_area = this->get_canvas();
140 }
141 
143 {
148  settings_ = nullptr;
149 }
151 {
153  input_program_color_ = get_input_socket_reader(0);
154  input_program_normal_ = get_input_socket_reader(1);
155  input_program_albedo_ = get_input_socket_reader(2);
156 }
157 
159 {
160  input_program_color_ = nullptr;
161  input_program_normal_ = nullptr;
162  input_program_albedo_ = nullptr;
164 }
165 
167 {
168  switch (settings->prefilter) {
170  case CMP_NODE_DENOISE_PREFILTER_ACCURATE: /* Prefiltered with #DenoisePrefilterOperation. */
171  return true;
173  default:
174  return false;
175  }
176 }
177 
179 {
180  if (settings_) {
181  hash_params((int)settings_->hdr, are_guiding_passes_noise_free(settings_));
182  }
183 }
184 
186 {
187  MemoryBuffer *tile_color = (MemoryBuffer *)input_program_color_->initialize_tile_data(rect2);
188  MemoryBuffer *tile_normal = (MemoryBuffer *)input_program_normal_->initialize_tile_data(rect2);
189  MemoryBuffer *tile_albedo = (MemoryBuffer *)input_program_albedo_->initialize_tile_data(rect2);
190  rcti rect;
191  rect.xmin = 0;
192  rect.ymin = 0;
193  rect.xmax = get_width();
194  rect.ymax = get_height();
196  this->generate_denoise(result, tile_color, tile_normal, tile_albedo, settings_);
197  return result;
198 }
199 
201  MemoryBuffer *input_color,
202  MemoryBuffer *input_normal,
203  MemoryBuffer *input_albedo,
204  NodeDenoise *settings)
205 {
206  BLI_assert(input_color->get_buffer());
207  if (!input_color->get_buffer()) {
208  return;
209  }
210 
212  /* OpenImageDenoise needs full buffers. */
213  MemoryBuffer *buf_color = input_color->is_a_single_elem() ? input_color->inflate() : input_color;
214  MemoryBuffer *buf_normal = input_normal && input_normal->is_a_single_elem() ?
215  input_normal->inflate() :
216  input_normal;
217  MemoryBuffer *buf_albedo = input_albedo && input_albedo->is_a_single_elem() ?
218  input_albedo->inflate() :
219  input_albedo;
220 
222  filter.init_and_lock_denoiser(output);
223 
224  filter.set_image("color", buf_color);
225  filter.set_image("normal", buf_normal);
226  filter.set_image("albedo", buf_albedo);
227 
228  BLI_assert(settings);
229  if (settings) {
230  filter.set("hdr", settings->hdr);
231  filter.set("srgb", false);
232  filter.set("cleanAux", are_guiding_passes_noise_free(settings));
233  }
234 
235  filter.execute();
236  filter.deinit_and_unlock_denoiser();
237 
238  /* Copy the alpha channel, OpenImageDenoise currently only supports RGB. */
239  output->copy_from(input_color, input_color->get_rect(), 3, COM_DATA_TYPE_VALUE_CHANNELS, 3);
240 
241  /* Delete inflated buffers. */
242  if (input_color->is_a_single_elem()) {
243  delete buf_color;
244  }
245  if (input_normal && input_normal->is_a_single_elem()) {
246  delete buf_normal;
247  }
248  if (input_albedo && input_albedo->is_a_single_elem()) {
249  delete buf_albedo;
250  }
251 }
252 
254  const rcti &UNUSED(area),
256 {
257  if (!output_rendered_) {
258  this->generate_denoise(output, inputs[0], inputs[1], inputs[2], settings_);
259  output_rendered_ = true;
260  }
261 }
262 
264 {
265  this->add_input_socket(data_type);
266  this->add_output_socket(data_type);
267  image_name_ = "";
268 }
269 
271 {
272  hash_param(image_name_);
273 }
274 
276 {
278  rcti rect;
279  BLI_rcti_init(&rect, 0, get_width(), 0, get_height());
280 
281  MemoryBuffer *result = new MemoryBuffer(get_output_socket()->get_data_type(), rect);
282  generate_denoise(result, input);
283 
284  return result;
285 }
286 
287 void DenoisePrefilterOperation::generate_denoise(MemoryBuffer *output, MemoryBuffer *input)
288 {
290 
291  /* Denoising needs full buffers. */
292  MemoryBuffer *input_buf = input->is_a_single_elem() ? input->inflate() : input;
293 
295  filter.init_and_lock_denoiser(output);
296  filter.set_image(image_name_, input_buf);
297  filter.execute();
298  filter.deinit_and_unlock_denoiser();
299 
300  /* Delete inflated buffers. */
301  if (input->is_a_single_elem()) {
302  delete input_buf;
303  }
304 }
305 
307  const rcti &UNUSED(area),
309 {
310  if (!output_rendered_) {
311  this->generate_denoise(output, inputs[0]);
312  output_rendered_ = true;
313  }
314 }
315 
316 } // namespace blender::compositor
#define BLI_assert(a)
Definition: BLI_assert.h:46
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
int BLI_cpu_support_sse41(void)
Definition: system.c:136
#define BLI_MUTEX_INITIALIZER
Definition: BLI_threads.h:83
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:373
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:378
#define UNUSED(x)
@ CMP_NODE_DENOISE_PREFILTER_FAST
@ CMP_NODE_DENOISE_PREFILTER_NONE
@ CMP_NODE_DENOISE_PREFILTER_ACCURATE
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
void set(const StringRef UNUSED(option_name), T UNUSED(value))
void init_and_lock_denoiser(MemoryBuffer *UNUSED(output))
void set_image(const StringRef UNUSED(name), MemoryBuffer *UNUSED(buffer))
MemoryBuffer * create_memory_buffer(rcti *rect) override
void update_memory_buffer(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void generate_denoise(MemoryBuffer *output, MemoryBuffer *input_color, MemoryBuffer *input_normal, MemoryBuffer *input_albedo, NodeDenoise *settings)
MemoryBuffer * create_memory_buffer(rcti *rect) override
void update_memory_buffer(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
a MemoryBuffer contains access to the data of a chunk
const rcti & get_rect() const
get the rect of this MemoryBuffer
float * get_buffer()
get the data of this MemoryBuffer
void add_output_socket(DataType datatype)
SocketReader * get_input_socket_reader(unsigned int index)
NodeOperationOutput * get_output_socket(unsigned int index=0)
NodeOperation * get_input_operation(int index)
virtual bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
void hash_params(T1 param1, T2 param2)
virtual void * initialize_tile_data(rcti *)
DataType
possible data types for sockets
Definition: COM_defines.h:30
@ Vector
Vector data type.
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
ccl_global float * buffer
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
#define T
static void area(int d1, int d2, int e1, int e2, float weights[2])
static bool are_guiding_passes_noise_free(NodeDenoise *settings)
constexpr int COM_DATA_TYPE_VALUE_CHANNELS
Definition: COM_defines.h:60
static bNodeSocketTemplate inputs[]
DepsgraphFromIDsFilter filter_
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63