Blender V5.0
node_exec.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DNA_node_types.h"
10
11#include "BLI_listbase.h"
12#include "BLI_utildefines.h"
13
14#include "BKE_global.hh"
15#include "BKE_node_runtime.hh"
18
19#include "MEM_guardedalloc.h"
20
21#include "node_exec.hh"
22#include "node_util.hh"
23
25{
26 /* NOTE: INT and BOOL supported as FLOAT. Only for EEVEE. */
28}
29
31{
32 if (stack && sock && sock->stack_index >= 0) {
33 return stack + sock->stack_index;
34 }
35 return nullptr;
36}
37
39{
40 /* build pointer stack */
41 if (in) {
42 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
43 *(in++) = node_get_socket_stack(stack, sock);
44 }
45 }
46
47 if (out) {
48 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
49 *(out++) = node_get_socket_stack(stack, sock);
50 }
51 }
52}
53
54static void node_init_input_index(bNodeSocket *sock, int *index)
55{
56 /* Only consider existing link when the `from` socket is valid! */
57 if (sock->link && !(sock->link->flag & NODE_LINK_MUTED) && sock->link->fromsock &&
58 sock->link->fromsock->stack_index >= 0)
59 {
60 sock->stack_index = sock->link->fromsock->stack_index;
61 }
62 else {
64 sock->stack_index = (*index)++;
65 }
66 else {
67 sock->stack_index = -1;
68 }
69 }
70}
71
73 int *index,
74 const blender::MutableSpan<bNodeLink> internal_links)
75{
76 const bNodeLink *link;
77 /* copy the stack index from internally connected input to skip the node */
78 for (bNodeLink &iter_link : internal_links) {
79 if (iter_link.tosock == sock) {
80 sock->stack_index = iter_link.fromsock->stack_index;
81 /* set the link pointer to indicate that this socket
82 * should not overwrite the stack value!
83 */
84 sock->link = &iter_link;
85 link = &iter_link;
86 break;
87 }
88 }
89 /* if not internally connected, assign a new stack index anyway to avoid bad stack access */
90 if (!link) {
92 sock->stack_index = (*index)++;
93 }
94 else {
95 sock->stack_index = -1;
96 }
97 }
98}
99
100static void node_init_output_index(bNodeSocket *sock, int *index)
101{
102 if (node_exec_socket_use_stack(sock)) {
103 sock->stack_index = (*index)++;
104 }
105 else {
106 sock->stack_index = -1;
107 }
108}
109
110/* basic preparation of socket stacks */
111static bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
112{
113 bNodeStack *ns = node_get_socket_stack(stack, sock);
114 if (!ns) {
115 return nullptr;
116 }
117
118 /* don't mess with remote socket stacks, these are initialized by other nodes! */
119 if (sock->link && !(sock->link->flag & NODE_LINK_MUTED)) {
120 return ns;
121 }
122
123 ns->sockettype = sock->type;
124
125 switch (sock->type) {
126 case SOCK_INT:
127 ns->vec[0] = node_socket_get_int(ntree, node, sock);
128 break;
129 case SOCK_BOOLEAN:
130 ns->vec[0] = node_socket_get_bool(ntree, node, sock);
131 break;
132 case SOCK_FLOAT:
133 ns->vec[0] = node_socket_get_float(ntree, node, sock);
134 break;
135 case SOCK_VECTOR:
136 node_socket_get_vector(ntree, node, sock, ns->vec);
137 break;
138 case SOCK_RGBA:
139 node_socket_get_color(ntree, node, sock, ns->vec);
140 break;
141 }
142
143 return ns;
144}
145
147{
148 using namespace blender;
149 ntree.ensure_topology_cache();
150 Vector<bNode *> nodes = ntree.toposort_left_to_right();
151 const bke::bNodeTreeZones *zones = ntree.zones();
152 if (!zones) {
153 return nodes;
154 }
155 /* Insertion sort to make sure that all nodes in a zone are packed together right before the zone
156 * output. */
157 for (int old_i = nodes.size() - 1; old_i >= 0; old_i--) {
158 bNode *node = nodes[old_i];
159 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node->identifier);
160 if (!zone) {
161 /* Nones outside of any zone can stay where they are. */
162 continue;
163 }
164 if (zone->output_node_id == node->identifier) {
165 /* The output of a zone should not be moved. */
166 continue;
167 }
168 for (int new_i = old_i + 1; new_i < nodes.size(); new_i++) {
169 bNode *next_node = nodes[new_i];
170 const bke::bNodeTreeZone *zone_to_check = zones->get_zone_by_node(next_node->identifier);
171 if (zone_to_check &&
172 (zone == zone_to_check || zone->contains_zone_recursively(*zone_to_check)))
173 {
174 /* Don't move the node further than the next node in the zone. */
175 break;
176 }
177 std::swap(nodes[new_i - 1], nodes[new_i]);
178 }
179 }
180 return nodes;
181}
182
184 bNodeTree *ntree,
185 bNodeInstanceKey parent_key)
186{
187 using namespace blender;
189 bNode *node;
190 bNodeExec *nodeexec;
191 bNodeInstanceKey nodekey;
192 bNodeStack *ns;
193 int index;
194 /* XXX: texture-nodes have threading issues with muting, have to disable it there. */
195
196 /* ensure all sock->link pointers and node levels are correct */
197 /* Using global main here is likely totally wrong, not sure what to do about that one though...
198 * We cannot even check ntree is in global main,
199 * since most of the time it won't be (thanks to ntree design)!!! */
201
202 ntree->ensure_topology_cache();
203 Vector<bNode *> nodelist = get_node_code_gen_order(*ntree);
204
205 /* XXX could let callbacks do this for specialized data */
206 exec = MEM_callocN<bNodeTreeExec>("node tree execution data");
207 /* Back-pointer to node tree. */
208 exec->nodetree = ntree;
209
210 /* set stack indices */
211 index = 0;
212 for (const int n : nodelist.index_range()) {
213 node = nodelist[n];
214
215 /* init node socket stack indexes */
216 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
217 node_init_input_index(sock, &index);
218 }
219
220 if (node->is_muted() || node->is_reroute()) {
221 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
222 node_init_output_index_muted(sock, &index, node->runtime->internal_links);
223 }
224 }
225 else {
226 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
227 node_init_output_index(sock, &index);
228 }
229 }
230 }
231
232 /* allocated exec data pointers for nodes */
233 exec->totnodes = nodelist.size();
234 exec->nodeexec = MEM_calloc_arrayN<bNodeExec>(exec->totnodes, "node execution data");
235 /* allocate data pointer for node stack */
236 exec->stacksize = index;
237 exec->stack = MEM_calloc_arrayN<bNodeStack>(exec->stacksize, "bNodeStack");
238
239 /* all non-const results are considered inputs */
240 int n;
241 for (n = 0; n < exec->stacksize; n++) {
242 exec->stack[n].hasinput = 1;
243 }
244
245 /* prepare all nodes for execution */
246 for (n = 0, nodeexec = exec->nodeexec; n < nodelist.size(); n++, nodeexec++) {
247 node = nodeexec->node = nodelist[n];
248 nodeexec->free_exec_fn = node->typeinfo->free_exec_fn;
249
250 /* tag inputs */
251 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
252 /* disable the node if an input link is invalid */
253 if (sock->link && !(sock->link->flag & NODE_LINK_VALID)) {
254 node->runtime->need_exec = 0;
255 }
256
257 ns = setup_stack(exec->stack, ntree, node, sock);
258 if (ns) {
259 ns->hasoutput = 1;
260 }
261 }
262
263 /* tag all outputs */
264 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
265 /* ns = */ setup_stack(exec->stack, ntree, node, sock);
266 }
267
268 nodekey = bke::node_instance_key(parent_key, ntree, node);
269 if (node->typeinfo->init_exec_fn) {
270 nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey);
271 }
272 }
273
274 return exec;
275}
276
278{
279 bNodeExec *nodeexec;
280 int n;
281
282 if (exec->stack) {
283 MEM_freeN(exec->stack);
284 }
285
286 for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
287 if (nodeexec->free_exec_fn) {
288 nodeexec->free_exec_fn(nodeexec->data.data);
289 }
290 }
291
292 if (exec->nodeexec) {
293 MEM_freeN(exec->nodeexec);
294 }
295
297}
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams &params={})
#define LISTBASE_FOREACH(type, var, list)
#define ELEM(...)
@ NODE_LINK_MUTED
@ NODE_LINK_VALID
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_SHADER
@ SOCK_FLOAT
@ SOCK_RGBA
Read Guarded memory(de)allocation.
int64_t size() const
IndexRange index_range() const
bool contains_zone_recursively(const bNodeTreeZone &other_zone) const
std::optional< int > output_node_id
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
#define in
#define out
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
bNodeInstanceKey node_instance_key(bNodeInstanceKey parent_key, const bNodeTree *ntree, const bNode *node)
Definition node.cc:4867
bNodeTreeExec * ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNodeInstanceKey parent_key)
Definition node_exec.cc:183
void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
Definition node_exec.cc:38
static void node_init_output_index(bNodeSocket *sock, int *index)
Definition node_exec.cc:100
bNodeStack * node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock)
Definition node_exec.cc:30
static void node_init_input_index(bNodeSocket *sock, int *index)
Definition node_exec.cc:54
static bNodeStack * setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
Definition node_exec.cc:111
static blender::Vector< bNode * > get_node_code_gen_order(bNodeTree &ntree)
Definition node_exec.cc:146
static void node_init_output_index_muted(bNodeSocket *sock, int *index, const blender::MutableSpan< bNodeLink > internal_links)
Definition node_exec.cc:72
static int node_exec_socket_use_stack(bNodeSocket *sock)
Definition node_exec.cc:24
void ntree_exec_end(bNodeTreeExec *exec)
Definition node_exec.cc:277
static void exec(void *data, int, bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
bool node_socket_get_bool(bNodeTree *ntree, bNode *, bNodeSocket *sock)
Definition node_util.cc:289
int node_socket_get_int(bNodeTree *ntree, bNode *, bNodeSocket *sock)
Definition node_util.cc:277
void node_socket_get_color(bNodeTree *ntree, bNode *, bNodeSocket *sock, float *value)
Definition node_util.cc:313
float node_socket_get_float(bNodeTree *ntree, bNode *, bNodeSocket *sock)
Definition node_util.cc:301
void node_socket_get_vector(bNodeTree *ntree, bNode *, bNodeSocket *sock, float *value)
Definition node_util.cc:328
bNodeExecData data
Definition node_exec.hh:25
bNode * node
Definition node_exec.hh:24
blender::bke::NodeFreeExecFunction free_exec_fn
Definition node_exec.hh:28
struct bNodeLink * link
float vec[4]
bNodeTypeHandle * typeinfo
ListBase inputs
bNodeRuntimeHandle * runtime
ListBase outputs
int32_t identifier