Blender V4.5
node_composite_viewer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_bounds_types.hh"
11
12#include "BKE_global.hh"
13#include "BKE_image.hh"
14
15#include "RNA_access.hh"
16
17#include "UI_interface.hh"
18#include "UI_resources.hh"
19
20#include "GPU_shader.hh"
21#include "GPU_texture.hh"
22
23#include "COM_node_operation.hh"
24#include "COM_utilities.hh"
25
27
28/* **************** VIEWER ******************** */
29
31
33{
34 b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
35}
36
37static void node_composit_init_viewer(bNodeTree * /*ntree*/, bNode *node)
38{
39 ImageUser *iuser = MEM_callocN<ImageUser>(__func__);
40 node->storage = iuser;
41 iuser->sfra = 1;
43
44 node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
45}
46
47using namespace blender::compositor;
48
50 public:
52
53 void execute() override
54 {
55 /* Viewers are treated as composite outputs that should be in the bounds of the compositing
56 * region, so do nothing if the compositing region is invalid. */
57 if (this->context().treat_viewer_as_composite_output() &&
58 !this->context().is_valid_compositing_region())
59 {
60 return;
61 }
62
63 const Result &image = this->get_input("Image");
64 if (image.is_single_value()) {
65 this->execute_clear();
66 }
67 else {
68 this->execute_copy();
69 }
70 }
71
73 {
74 const Result &image = this->get_input("Image");
75
77
78 const Domain domain = this->compute_domain();
80 domain, image.meta_data.is_non_color_data, image.precision());
81 if (this->context().use_gpu()) {
83 }
84 else {
85 parallel_for(domain.size, [&](const int2 texel) { output.store_pixel(texel, color); });
86 }
87 }
88
90 {
91 if (this->context().use_gpu()) {
92 this->execute_copy_gpu();
93 }
94 else {
95 this->execute_copy_cpu();
96 }
97 }
98
100 {
101 const Result &image = this->get_input("Image");
102 const Domain domain = this->compute_domain();
104 domain, image.meta_data.is_non_color_data, image.precision());
105
106 GPUShader *shader = this->context().get_shader("compositor_write_output", output.precision());
107 GPU_shader_bind(shader);
108
109 const Bounds<int2> bounds = this->get_output_bounds();
110 GPU_shader_uniform_2iv(shader, "lower_bound", bounds.min);
111 GPU_shader_uniform_2iv(shader, "upper_bound", bounds.max);
112
113 image.bind_as_texture(shader, "input_tx");
114
115 output.bind_as_image(shader, "output_img");
116
118
119 image.unbind_as_texture();
120 output.unbind_as_image();
122 }
123
125 {
126 const Domain domain = this->compute_domain();
127 const Result &image = this->get_input("Image");
129 domain, image.meta_data.is_non_color_data, image.precision());
130
131 const Bounds<int2> bounds = this->get_output_bounds();
132 parallel_for(domain.size, [&](const int2 texel) {
133 const int2 output_texel = texel + bounds.min;
134 if (output_texel.x > bounds.max.x || output_texel.y > bounds.max.y) {
135 return;
136 }
137 output.store_pixel(texel + bounds.min, image.load_pixel<float4>(texel));
138 });
139 }
140
141 /* Returns the bounds of the area of the viewer, which might be limited to a smaller region of
142 * the output. */
144 {
145 /* Viewers are treated as composite outputs that should be in the bounds of the compositing
146 * region. */
147 if (context().treat_viewer_as_composite_output()) {
148 const rcti compositing_region = context().get_compositing_region();
149 return Bounds<int2>(int2(compositing_region.xmin, compositing_region.ymin),
150 int2(compositing_region.xmax, compositing_region.ymax));
151 }
152
153 /* Otherwise, use the bounds of the input as is. */
154 return Bounds<int2>(int2(0), compute_domain().size);
155 }
156
158 {
159 /* Viewers are treated as composite outputs that should be in the domain of the compositing
160 * region. */
161 if (context().treat_viewer_as_composite_output()) {
162 return Domain(context().get_compositing_region_size());
163 }
164
165 /* Otherwise, use the domain of the input as is. */
166 const Domain domain = NodeOperation::compute_domain();
167 /* Fall back to the compositing region size in case of a single value domain. */
168 return domain.size == int2(1) ? Domain(context().get_compositing_region_size()) : domain;
169 }
170};
171
173{
174 return new ViewerOperation(context, node);
175}
176
177} // namespace blender::nodes::node_composite_viewer_cc
178
180{
182
183 static blender::bke::bNodeType ntype;
184
185 cmp_node_type_base(&ntype, "CompositorNodeViewer", CMP_NODE_VIEWER);
186 ntype.ui_name = "Viewer";
187 ntype.ui_description =
188 "Visualize data from inside a node graph, in the image editor or as a backdrop";
189 ntype.enum_name_legacy = "VIEWER";
191 ntype.declare = file_ns::cmp_node_viewer_declare;
192 ntype.initfunc = file_ns::node_composit_init_viewer;
195 ntype.get_compositor_operation = file_ns::get_compositor_operation;
196
197 ntype.no_muting = true;
198
200}
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:434
#define CMP_NODE_VIEWER
@ IMA_TYPE_COMPOSITE
@ NODE_VIEWER_SHORTCUT_NONE
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
void GPU_shader_unbind()
void GPU_texture_clear(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
@ GPU_DATA_FLOAT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
virtual Result get_viewer_output_result(Domain domain, bool is_data, ResultPrecision precision)=0
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:138
virtual Domain compute_domain()
Definition operation.cc:56
static ResultPrecision precision(eGPUTextureFormat format)
Definition result.cc:166
void unbind_as_texture() const
Definition result.cc:389
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:365
T load_pixel(const int2 &texel) const
bool is_single_value() const
Definition result.cc:625
const T & get_single_value() const
#define output
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define G(x, y, z)
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5603
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:170
void parallel_for(const int2 range, const Function &function)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
static void node_composit_init_viewer(bNodeTree *, bNode *node)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
static void register_node_type_cmp_viewer()
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
Definition DNA_ID.h:404
int16_t custom1
struct ID * id
void * storage
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:336
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
const char * enum_name_legacy
Definition BKE_node.hh:235
NodeDeclareFunction declare
Definition BKE_node.hh:355
int ymin
int ymax
int xmin
int xmax