Blender V5.0
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_resources.hh"
18
19#include "GPU_shader.hh"
20#include "GPU_texture.hh"
21
22#include "COM_node_operation.hh"
23#include "COM_utilities.hh"
24
26
27/* **************** VIEWER ******************** */
28
30
32{
33 b.add_input<decl::Color>("Image")
34 .default_value({0.0f, 0.0f, 0.0f, 1.0f})
35 .structure_type(StructureType::Dynamic);
36}
37
38static void node_composit_init_viewer(bNodeTree * /*ntree*/, bNode *node)
39{
40 ImageUser *iuser = MEM_callocN<ImageUser>(__func__);
41 node->storage = iuser;
42 iuser->sfra = 1;
44}
45
46using namespace blender::compositor;
47
49 public:
51
52 void execute() override
53 {
54 /* Viewers are treated as composite outputs that should be in the bounds of the compositing
55 * region, so do nothing if the compositing region is invalid. */
56 if (this->context().treat_viewer_as_compositor_output() &&
57 !this->context().is_valid_compositing_region())
58 {
59 return;
60 }
61
62 const Result &image = this->get_input("Image");
63 if (image.is_single_value()) {
64 this->execute_clear();
65 }
66 else {
67 this->execute_copy();
68 }
69 }
70
72 {
73 const Result &image = this->get_input("Image");
74
76
77 const Domain domain = this->compute_domain();
79 domain, image.meta_data.is_non_color_data, image.precision());
80 if (this->context().use_gpu()) {
82 }
83 else {
84 parallel_for(domain.size, [&](const int2 texel) { output.store_pixel(texel, color); });
85 }
86 }
87
89 {
90 if (this->context().use_gpu()) {
91 this->execute_copy_gpu();
92 }
93 else {
94 this->execute_copy_cpu();
95 }
96 }
97
99 {
100 const Result &image = this->get_input("Image");
101 const Domain domain = this->compute_domain();
103 domain, image.meta_data.is_non_color_data, image.precision());
104
105 gpu::Shader *shader = this->context().get_shader("compositor_write_output",
106 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 (this->context().treat_viewer_as_compositor_output() &&
148 this->context().use_context_bounds_for_input_output())
149 {
150 return this->context().get_compositing_region();
151 }
152
153 /* Otherwise, use the bounds of the input as is. */
154 return Bounds<int2>(int2(0), this->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 (this->context().treat_viewer_as_compositor_output() &&
162 this->context().use_context_bounds_for_input_output())
163 {
164 return Domain(context().get_compositing_region_size());
165 }
166
167 /* Otherwise, use the domain of the input as is. */
168 const Domain domain = NodeOperation::compute_domain();
169 /* Fall back to the compositing region size in case of a single value domain. */
170 return domain.size == int2(1) ? Domain(context().get_compositing_region_size()) : domain;
171 }
172};
173
175{
176 return new ViewerOperation(context, node);
177}
178
179} // namespace blender::nodes::node_composite_viewer_cc
180
182{
184
185 static blender::bke::bNodeType ntype;
186
187 cmp_node_type_base(&ntype, "CompositorNodeViewer", CMP_NODE_VIEWER);
188 ntype.ui_name = "Viewer";
189 ntype.ui_description =
190 "Visualize data from inside a node graph, in the image editor or as a backdrop";
191 ntype.enum_name_legacy = "VIEWER";
193 ntype.declare = file_ns::cmp_node_viewer_declare;
194 ntype.initfunc = file_ns::node_composit_init_viewer;
197 ntype.get_compositor_operation = file_ns::get_compositor_operation;
198
199 ntype.no_muting = true;
200
202}
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:448
#define CMP_NODE_VIEWER
@ NODE_VIEWER_SHORTCUT_NONE
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_unbind()
void GPU_shader_uniform_2iv(blender::gpu::Shader *sh, const char *name, const int data[2])
void GPU_texture_clear(blender::gpu::Texture *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
virtual Result get_viewer_output(Domain domain, bool is_data, ResultPrecision precision)=0
gpu::Shader * get_shader(const char *info_name, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:138
virtual Domain compute_domain()
Definition operation.cc:56
void unbind_as_texture() const
Definition result.cc:511
void bind_as_texture(gpu::Shader *shader, const char *texture_name) const
Definition result.cc:487
T load_pixel(const int2 &texel) const
static ResultPrecision precision(blender::gpu::TextureFormat format)
Definition result.cc:233
bool is_single_value() const
Definition result.cc:758
const T & get_single_value() const
#define output
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
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:5414
void compute_dispatch_threads_at_least(gpu::Shader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:196
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
int16_t custom1
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:348
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362