Blender V4.3
node_composite_denoise.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_system.h"
10
11#include "MEM_guardedalloc.h"
12
13#include "UI_interface.hh"
14#include "UI_resources.hh"
15
16#include "GPU_state.hh"
17#include "GPU_texture.hh"
18
19#include "DNA_node_types.h"
20
21#include "COM_node_operation.hh"
22
24
25#ifdef WITH_OPENIMAGEDENOISE
26# include <OpenImageDenoise/oidn.hpp>
27#endif
28
30
32
34{
35 b.add_input<decl::Color>("Image")
36 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
37 .compositor_domain_priority(0);
38 b.add_input<decl::Vector>("Normal")
39 .default_value({0.0f, 0.0f, 0.0f})
40 .min(-1.0f)
41 .max(1.0f)
42 .hide_value()
43 .compositor_domain_priority(2);
44 b.add_input<decl::Color>("Albedo")
45 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
46 .hide_value()
48 b.add_output<decl::Color>("Image");
49}
50
51static void node_composit_init_denonise(bNodeTree * /*ntree*/, bNode *node)
52{
53 NodeDenoise *ndg = MEM_cnew<NodeDenoise>(__func__);
54 ndg->hdr = true;
56 node->storage = ndg;
57}
58
60{
61#ifndef WITH_OPENIMAGEDENOISE
62 uiItemL(layout, RPT_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
63#else
64 /* Always supported through Accelerate framework BNNS on macOS. */
65# ifndef __APPLE__
66 if (!BLI_cpu_support_sse42()) {
67 uiItemL(layout, RPT_("Disabled, CPU with SSE4.2 is required"), ICON_ERROR);
68 }
69# endif
70#endif
71
72 uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
73 uiItemR(layout, ptr, "prefilter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
74 uiItemR(layout, ptr, "use_hdr", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
75}
76
77using namespace blender::realtime_compositor;
78
79/* A callback to cancel the filter operations by evaluating the context's is_canceled method. The
80 * API specifies that true indicates the filter should continue, while false indicates it should
81 * stop, so invert the condition. This callback can also be used to track progress using the given
82 * n argument, but we currently don't make use of it. See OIDNProgressMonitorFunction in the API
83 * for more information. */
84[[maybe_unused]] static bool oidn_progress_monitor_function(void *user_ptr, double /*n*/)
85{
86 const Context *context = static_cast<const Context *>(user_ptr);
87 return !context->is_canceled();
88}
89
91 public:
93
94 void execute() override
95 {
96 Result &input_image = get_input("Image");
97 Result &output_image = get_result("Image");
98
99 if (!is_oidn_supported() || input_image.is_single_value()) {
100 input_image.pass_through(output_image);
101 return;
102 }
103
104#ifdef WITH_OPENIMAGEDENOISE
105 oidn::DeviceRef device = oidn::newDevice(oidn::DeviceType::CPU);
106 device.commit();
107
108 const int width = input_image.domain().size.x;
109 const int height = input_image.domain().size.y;
110 const int pixel_stride = sizeof(float) * 4;
111 const eGPUDataFormat data_format = GPU_DATA_FLOAT;
112
113 /* Download the input texture and set it as both the input and output of the filter to denoise
114 * it in-place. */
116 float *color = static_cast<float *>(GPU_texture_read(input_image, data_format, 0));
117 oidn::FilterRef filter = device.newFilter("RT");
118 filter.setImage("color", color, oidn::Format::Float3, width, height, 0, pixel_stride);
119 filter.setImage("output", color, oidn::Format::Float3, width, height, 0, pixel_stride);
120 filter.set("hdr", use_hdr());
121 filter.set("cleanAux", auxiliary_passes_are_clean());
122 filter.setProgressMonitorFunction(oidn_progress_monitor_function, &context());
123
124 /* If the albedo input is not a single value input, download the albedo texture, denoise it
125 * in-place if denoising auxiliary passes is needed, and set it to the main filter. */
126 float *albedo = nullptr;
127 Result &input_albedo = get_input("Albedo");
128 if (!input_albedo.is_single_value()) {
129 albedo = static_cast<float *>(GPU_texture_read(input_albedo, data_format, 0));
130
132 oidn::FilterRef albedoFilter = device.newFilter("RT");
133 albedoFilter.setImage(
134 "albedo", albedo, oidn::Format::Float3, width, height, 0, pixel_stride);
135 albedoFilter.setImage(
136 "output", albedo, oidn::Format::Float3, width, height, 0, pixel_stride);
137 albedoFilter.setProgressMonitorFunction(oidn_progress_monitor_function, &context());
138 albedoFilter.commit();
139 albedoFilter.execute();
140 }
141
142 filter.setImage("albedo", albedo, oidn::Format::Float3, width, height, 0, pixel_stride);
143 }
144
145 /* If the albedo and normal inputs are not single value inputs, download the normal texture,
146 * denoise it in-place if denoising auxiliary passes is needed, and set it to the main filter.
147 * Notice that we also consider the albedo input because OIDN doesn't support denoising with
148 * only the normal auxiliary pass. */
149 float *normal = nullptr;
150 Result &input_normal = get_input("Normal");
151 if (albedo && !input_normal.is_single_value()) {
152 normal = static_cast<float *>(GPU_texture_read(input_normal, data_format, 0));
153
155 oidn::FilterRef normalFilter = device.newFilter("RT");
156 normalFilter.setImage(
157 "normal", normal, oidn::Format::Float3, width, height, 0, pixel_stride);
158 normalFilter.setImage(
159 "output", normal, oidn::Format::Float3, width, height, 0, pixel_stride);
160 normalFilter.setProgressMonitorFunction(oidn_progress_monitor_function, &context());
161 normalFilter.commit();
162 normalFilter.execute();
163 }
164
165 filter.setImage("normal", normal, oidn::Format::Float3, width, height, 0, pixel_stride);
166 }
167
168 filter.commit();
169 filter.execute();
170
171 output_image.allocate_texture(input_image.domain());
172 GPU_texture_update(output_image, data_format, color);
173
174 MEM_freeN(color);
175 if (albedo) {
176 MEM_freeN(albedo);
177 }
178 if (normal) {
179 MEM_freeN(normal);
180 }
181#endif
182 }
183
184 /* If the pre-filter mode is set to CMP_NODE_DENOISE_PREFILTER_NONE, that it means the supplied
185 * auxiliary passes are already noise-free, if it is set to CMP_NODE_DENOISE_PREFILTER_ACCURATE,
186 * the auxiliary passes will be denoised before denoising the main image, so in both cases, the
187 * auxiliary passes are considered clean. If it is set to CMP_NODE_DENOISE_PREFILTER_FAST on the
188 * other hand, the auxiliary passes are assumed to be noisy and are thus not clean, and will be
189 * denoised while denoising the main image. */
194
195 /* Returns whether the auxiliary passes should be denoised, see the auxiliary_passes_are_clean
196 * method for more information. */
201
202 bool use_hdr()
203 {
204 return node_storage(bnode()).hdr;
205 }
206
208 {
209 return static_cast<CMPNodeDenoisePrefilter>(node_storage(bnode()).prefilter);
210 }
211
212 /* OIDN can be disabled as a build option, so check WITH_OPENIMAGEDENOISE. Additionally, it is
213 * only supported at runtime for CPUs that supports SSE4.1, except for MacOS where it is always
214 * supported through the Accelerate framework BNNS on macOS. */
216 {
217#ifndef WITH_OPENIMAGEDENOISE
218 return false;
219#else
220# ifdef __APPLE__
221 return true;
222# else
223 return BLI_cpu_support_sse42();
224# endif
225#endif
226 }
227};
228
230{
231 return new DenoiseOperation(context, node);
232}
233
234} // namespace blender::nodes::node_composite_denoise_cc
235
237{
239
240 static blender::bke::bNodeType ntype;
241
242 cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER);
243 ntype.declare = file_ns::cmp_node_denoise_declare;
244 ntype.draw_buttons = file_ns::node_composit_buts_denoise;
245 ntype.initfunc = file_ns::node_composit_init_denonise;
248 ntype.get_compositor_operation = file_ns::get_compositor_operation;
249
251}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:408
int BLI_cpu_support_sse42(void)
Definition system.c:160
#define RPT_(msgid)
#define IFACE_(msgid)
CMPNodeDenoisePrefilter
@ CMP_NODE_DENOISE_PREFILTER_FAST
@ CMP_NODE_DENOISE_PREFILTER_ACCURATE
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_TEXTURE_UPDATE
Definition GPU_state.hh:39
void * GPU_texture_read(GPUTexture *texture, eGPUDataFormat data_format, int mip_level)
eGPUDataFormat
@ GPU_DATA_FLOAT
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
Read Guarded memory(de)allocation.
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:144
Result & get_result(StringRef identifier)
Definition operation.cc:46
void pass_through(Result &target)
Definition result.cc:289
const Domain & domain() const
Definition result.cc:712
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static void node_composit_buts_denoise(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
static bool oidn_progress_monitor_function(void *user_ptr, double)
static void node_composit_init_denonise(bNodeTree *, bNode *node)
void register_node_type_cmp_denoise()
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
#define min(a, b)
Definition sort.c:32
Defines a node type.
Definition BKE_node.hh:218
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:324
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126