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