Blender V5.0
utilities.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <optional>
6
7#include "BLI_assert.h"
8#include "BLI_math_vector.hh"
10
11#include "DNA_node_types.h"
12
15
16#include "GPU_compute.hh"
17#include "GPU_shader.hh"
18
19#include "COM_result.hh"
20#include "COM_utilities.hh"
21
22namespace blender::compositor {
23
24using namespace nodes::derived_node_tree_types;
26
28{
29 return socket->is_available() && StringRef(socket->idname) != "NodeSocketVirtual";
30}
31
33{
34 /* The input is unlinked. Return the socket itself. */
35 if (!input->is_logically_linked()) {
36 return input;
37 }
38
39 /* Only a single origin socket is guaranteed to exist. */
40 DSocket socket;
41 input.foreach_origin_socket([&](const DSocket origin) { socket = origin; });
42
43 /* The origin socket might be null if it is an output of a group node whose group has no Group
44 * Output node. The input is thus considered to be unlinked logically. */
45 if (!socket) {
46 return input;
47 }
48
49 return socket;
50}
51
53{
54 /* Get the origin socket of this input, which will be an output socket if the input is linked
55 * to an output. */
57
58 /* If the origin socket is an input, that means the input is unlinked, so return a null output
59 * socket. */
60 if (origin->is_input()) {
61 return DOutputSocket();
62 }
63
64 /* Now that we know the origin is an output, return a derived output from it. */
65 return DOutputSocket(origin);
66}
67
69 const std::optional<int> dimensions)
70{
71 switch (data_type) {
72 case SOCK_FLOAT:
73 return ResultType::Float;
74 case SOCK_INT:
75 return ResultType::Int;
76 case SOCK_BOOLEAN:
77 return ResultType::Bool;
78 case SOCK_VECTOR:
79 switch (dimensions.value_or(3)) {
80 case 2:
81 return ResultType::Float2;
82 case 3:
83 return ResultType::Float3;
84 case 4:
85 return ResultType::Float4;
86 default:
88 return ResultType::Float;
89 }
90 case SOCK_RGBA:
91 return ResultType::Color;
92 case SOCK_MENU:
93 return ResultType::Menu;
94 case SOCK_STRING:
95 return ResultType::String;
96 default:
98 return ResultType::Float;
99 }
100}
101
103{
104 const eNodeSocketDatatype socket_type = static_cast<eNodeSocketDatatype>(socket->type);
105 if (socket_type == SOCK_VECTOR) {
107 socket_type, socket->default_value_typed<bNodeSocketValueVector>()->dimensions);
108 }
109
110 return socket_data_type_to_result_type(socket_type);
111}
112
114{
115 bool condition_satisfied = false;
116 output.foreach_target_socket(
117 [&](DInputSocket target, const TargetSocketPathInfo & /*path_info*/) {
118 if (condition(target.node())) {
119 condition_satisfied = true;
120 return;
121 }
122 });
123 return condition_satisfied;
124}
125
127 FunctionRef<bool(DInputSocket)> condition)
128{
129 if (!output->is_logically_linked()) {
130 return 0;
131 }
132
133 int count = 0;
134 output.foreach_target_socket(
135 [&](DInputSocket target, const TargetSocketPathInfo & /*path_info*/) {
136 if (condition(target)) {
137 count++;
138 }
139 });
140 return count;
141}
142
144{
145 BLI_assert(bool(node->typeinfo->gpu_fn) == bool(node->typeinfo->build_multi_function));
146 return node->typeinfo->gpu_fn && node->typeinfo->build_multi_function;
147}
148
150{
151 /* We only support implicit textures coordinates, though this can be expanded in the future. */
152 if (socket_declaration->input_field_type == nodes::InputSocketFieldType::Implicit) {
154 }
155 return ImplicitInput::None;
156}
157
159 const nodes::SocketDeclaration *socket_declaration)
160{
161 /* Negative priority means no priority is set and we fall back to the index, that is, we
162 * prioritize inputs according to their order. */
163 if (socket_declaration->compositor_domain_priority() < 0) {
164 return input->index();
165 }
166 return socket_declaration->compositor_domain_priority();
167}
168
170{
171 using namespace nodes;
172 InputDescriptor input_descriptor;
173 input_descriptor.type = get_node_socket_result_type(socket);
174
175 /* Default to the index of the input as its domain priority in case the node does not have a
176 * declaration. */
177 input_descriptor.domain_priority = socket->index();
178
179 /* Not every node has a declaration, in which case we assume the default values for the rest of
180 * the properties. */
181 const NodeDeclaration *node_declaration = socket->owner_node().declaration();
182 if (!node_declaration) {
183 return input_descriptor;
184 }
185 const SocketDeclaration *socket_declaration = node_declaration->inputs[socket->index()];
186 input_descriptor.domain_priority = get_domain_priority(socket, socket_declaration);
187 input_descriptor.expects_single_value = socket_declaration->structure_type ==
188 StructureType::Single;
189 input_descriptor.realization_mode = static_cast<InputRealizationMode>(
190 socket_declaration->compositor_realization_mode());
191 input_descriptor.implicit_input = get_implicit_input(socket_declaration);
192
193 return input_descriptor;
194}
195
196void compute_dispatch_threads_at_least(gpu::Shader *shader, int2 threads_range, int2 local_size)
197{
198 /* If the threads range is divisible by the local size, dispatch the number of needed groups,
199 * which is their division. If it is not divisible, then dispatch an extra group to cover the
200 * remaining invocations, which means the actual threads range of the dispatch will be a bit
201 * larger than the given one. */
202 const int2 groups_to_dispatch = math::divide_ceil(threads_range, local_size);
203 GPU_compute_dispatch(shader, groups_to_dispatch.x, groups_to_dispatch.y, 1);
204}
205
207{
208 if (!(node->flag & NODE_PREVIEW)) {
209 return false;
210 }
211
212 if (node->flag & NODE_COLLAPSED) {
213 return false;
214 }
215
216 /* Only compute previews for nodes in the active context. */
217 if (node.context()->instance_key().value !=
218 node.context()->derived_tree().active_context().instance_key().value)
219 {
220 return false;
221 }
222
223 return true;
224}
225
227{
228 if (!is_node_preview_needed(node)) {
229 return DOutputSocket();
230 }
231
232 for (const bNodeSocket *output : node->output_sockets()) {
234 continue;
235 }
236
237 if (output->is_logically_linked()) {
238 return DOutputSocket(node.context(), output);
239 }
240 }
241
242 return DOutputSocket();
243}
244
245} // namespace blender::compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
@ NODE_COLLAPSED
@ NODE_PREVIEW
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
void GPU_compute_dispatch(blender::gpu::Shader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
Vector< SocketDeclaration * > inputs
const CompositorInputRealizationMode & compositor_realization_mode() const
#define input
#define output
int count
int number_of_inputs_linked_to_output_conditioned(DOutputSocket output, FunctionRef< bool(DInputSocket)> condition)
Definition utilities.cc:126
ResultType socket_data_type_to_result_type(const eNodeSocketDatatype data_type, const std::optional< int > dimensions=std::nullopt)
Definition utilities.cc:68
bool is_output_linked_to_node_conditioned(DOutputSocket output, FunctionRef< bool(DNode)> condition)
Definition utilities.cc:113
void compute_dispatch_threads_at_least(gpu::Shader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:196
DSocket get_input_origin_socket(DInputSocket input)
Definition utilities.cc:32
DOutputSocket::TargetSocketPathInfo TargetSocketPathInfo
Definition utilities.cc:25
static int get_domain_priority(const bNodeSocket *input, const nodes::SocketDeclaration *socket_declaration)
Definition utilities.cc:158
static ImplicitInput get_implicit_input(const nodes::SocketDeclaration *socket_declaration)
Definition utilities.cc:149
DOutputSocket find_preview_output_socket(const DNode &node)
Definition utilities.cc:226
ResultType get_node_socket_result_type(const bNodeSocket *socket)
Definition utilities.cc:102
DOutputSocket get_output_linked_to_input(DInputSocket input)
Definition utilities.cc:52
InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
Definition utilities.cc:169
bool is_pixel_node(DNode node)
Definition utilities.cc:143
bool is_socket_available(const bNodeSocket *socket)
Definition utilities.cc:27
bool is_node_preview_needed(const DNode &node)
Definition utilities.cc:206
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< int32_t, 2 > int2
char idname[64]