Blender V5.0
node_tree_structure_type_inferencing.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_array_utils.hh"
6#include "BLI_bit_span_ops.hh"
7#include "BLI_bit_vector.hh"
8#include "BLI_stack.hh"
9#include "BLI_utildefines.h"
10
11#include "BKE_node.hh"
13#include "BKE_node_runtime.hh"
15
17#include "DNA_node_types.h"
18
20#include "NOD_socket.hh"
21
23
24using nodes::StructureType;
25namespace aal = nodes::anonymous_attribute_lifetime;
26
28{
29 const Span<const bNodeSocket *> input_sockets = node.input_sockets();
30 const Span<const bNodeSocket *> output_sockets = node.output_sockets();
31
33 node_interface.inputs.reinitialize(input_sockets.size());
34 node_interface.outputs.reinitialize(output_sockets.size());
35
36 if (node.is_undefined() || !node.declaration() || node.declaration()->skip_updating_sockets) {
37 node_interface.inputs.fill(StructureType::Dynamic);
38 node_interface.outputs.fill(
40 return node_interface;
41 }
42 if (node.is_reroute()) {
43 node_interface.inputs.first() = StructureType::Dynamic;
44 node_interface.outputs.first() = {StructureType::Dynamic, {0}};
45 return node_interface;
46 }
47
48 for (const int i : input_sockets.index_range()) {
49 const nodes::SocketDeclaration &decl = *input_sockets[i]->runtime->declaration;
50 node_interface.inputs[i] = decl.structure_type;
51 }
52
53 for (const int output : output_sockets.index_range()) {
54 const nodes::SocketDeclaration &decl = *output_sockets[output]->runtime->declaration;
56 dependency.type = decl.structure_type;
57 if (dependency.type != StructureType::Dynamic) {
58 continue;
59 }
60
61 /* Currently the input sockets that influence the field status of an output are the same as the
62 * sockets that influence its structure type. Reuse that for the propagation of structure type
63 * until there is a more generic format of intra-node dependencies. */
64 switch (decl.output_field_dependency.field_type()) {
66 break;
68 break;
70 dependency.linked_inputs.reinitialize(input_sockets.size());
72 break;
75 break;
76 }
77 }
78
79 return node_interface;
80}
81
83{
84 const Span<const bNode *> nodes = tree.all_nodes();
86 for (const int i : nodes.index_range()) {
87 interfaces[i] = calc_node_interface(*nodes[i]);
88 }
89 return interfaces;
90}
91
92enum class DataRequirement : int8_t { None, Field, Single, Grid, List, Invalid };
93
95{
96 if (a == b) {
97 return a;
98 }
99 if (a == DataRequirement::None) {
100 return b;
101 }
102 if (b == DataRequirement::None) {
103 return a;
104 }
107 {
108 /* Single beats field, because fields can accept single values too. */
110 }
112}
113
114static StructureType data_requirement_to_auto_structure_type(const DataRequirement requirement)
115{
116 switch (requirement) {
118 return StructureType::Dynamic;
120 return StructureType::Field;
122 return StructureType::Single;
124 return StructureType::Grid;
126 return StructureType::List;
128 return StructureType::Dynamic;
129 }
131 return StructureType::Dynamic;
132}
133
135 bits::MutableBoundedBitSpan is_auto_structure_type)
136{
137 /* Handle group inputs. */
138 for (const int i : tree.interface_inputs().index_range()) {
139 const bNodeTreeInterfaceSocket &io_socket = *tree.interface_inputs()[i];
141 continue;
142 }
143 for (const bNode *node : tree.group_input_nodes()) {
144 const bNodeSocket &socket = node->output_socket(i);
145 is_auto_structure_type[socket.index_in_tree()].set();
146 }
147 }
148
149 /* Handle group outputs. */
150 if (const bNode *group_output_node = tree.group_output_node()) {
151 is_auto_structure_type.slice(group_output_node->input_socket_indices_in_tree().drop_back(1))
152 .set_all();
153 }
154
155 /* Handle closure inputs and outputs. */
157 for (const bNode *closure_input_node : tree.nodes_by_type("NodeClosureInput")) {
158 const auto *closure_output_node = closure_zone_type->get_corresponding_output(
159 tree, *closure_input_node);
160 if (!closure_output_node) {
161 continue;
162 }
163 const auto &storage = *static_cast<const NodeClosureOutput *>(closure_output_node->storage);
164 for (const int i : IndexRange(storage.input_items.items_num)) {
165 const NodeClosureInputItem &item = storage.input_items.items[i];
167 const bNodeSocket &socket = closure_input_node->output_socket(i);
168 is_auto_structure_type[socket.index_in_tree()].set();
169 }
170 }
171 for (const int i : IndexRange(storage.output_items.items_num)) {
172 const NodeClosureOutputItem &item = storage.output_items.items[i];
174 const bNodeSocket &socket = closure_output_node->input_socket(i);
175 is_auto_structure_type[socket.index_in_tree()].set();
176 }
177 }
178 }
179
180 /* Handle Evaluate Closure nodes. */
181 for (const bNode *evaluate_closure_node : tree.nodes_by_type("NodeEvaluateClosure")) {
182 auto &storage = *static_cast<NodeEvaluateClosure *>(evaluate_closure_node->storage);
183 for (const int i : IndexRange(storage.input_items.items_num)) {
184 const NodeEvaluateClosureInputItem &item = storage.input_items.items[i];
186 const bNodeSocket &socket = evaluate_closure_node->input_socket(i + 1);
187 is_auto_structure_type[socket.index_in_tree()].set();
188 }
189 }
190 for (const int i : IndexRange(storage.output_items.items_num)) {
191 const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
193 const bNodeSocket &socket = evaluate_closure_node->output_socket(i);
194 is_auto_structure_type[socket.index_in_tree()].set();
195 }
196 }
197 }
198
199 /* Handle Combine Bundle nodes. */
200 for (const bNode *node : tree.nodes_by_type("NodeCombineBundle")) {
201 auto &storage = *static_cast<NodeCombineBundle *>(node->storage);
202 for (const int i : IndexRange(storage.items_num)) {
203 const NodeCombineBundleItem &item = storage.items[i];
205 const bNodeSocket &socket = node->input_socket(i);
206 is_auto_structure_type[socket.index_in_tree()].set();
207 }
208 }
209 }
210
211 /* Handle Separate Bundle nodes. */
212 for (const bNode *node : tree.nodes_by_type("NodeSeparateBundle")) {
213 auto &storage = *static_cast<NodeSeparateBundle *>(node->storage);
214 for (const int i : IndexRange(storage.items_num)) {
215 const NodeSeparateBundleItem &item = storage.items[i];
217 const bNodeSocket &socket = node->output_socket(i);
218 is_auto_structure_type[socket.index_in_tree()].set();
219 }
220 }
221 }
222}
223
225 const bits::BoundedBitSpan is_auto_structure_type,
226 MutableSpan<DataRequirement> input_requirements)
227{
228 for (const bNode *node : tree.all_nodes()) {
229 for (const bNodeSocket *socket : node->input_sockets()) {
230 DataRequirement &requirement = input_requirements[socket->index_in_all_inputs()];
231 if (is_auto_structure_type[socket->index_in_tree()]) {
232 requirement = DataRequirement::None;
233 continue;
234 }
235 const nodes::SocketDeclaration *declaration = socket->runtime->declaration;
236 if (!declaration) {
237 requirement = DataRequirement::None;
238 continue;
239 }
241 requirement = DataRequirement::Single;
242 continue;
243 }
244 switch (declaration->structure_type) {
245 case StructureType::Dynamic: {
246 requirement = DataRequirement::None;
247 break;
248 }
249 case StructureType::Single: {
250 requirement = DataRequirement::Single;
251 break;
252 }
253 case StructureType::Grid: {
254 requirement = DataRequirement::Grid;
255 break;
256 }
257 case StructureType::Field: {
258 requirement = DataRequirement::Field;
259 break;
260 }
261 case StructureType::List: {
262 requirement = DataRequirement::List;
263 break;
264 }
265 }
266 }
267 }
268}
269
271 const bNodeSocket &output_socket, const Span<DataRequirement> input_requirements)
272{
274 if (!output_socket.is_available()) {
275 return requirement;
276 }
277 for (const bNodeSocket *socket : output_socket.directly_linked_sockets()) {
278 if (!socket->is_available()) {
279 continue;
280 }
281 requirement = merge(requirement, input_requirements[socket->index_in_all_inputs()]);
282 }
283 return requirement;
284}
285
287 const Span<DataRequirement> input_requirements,
288 nodes::StructureTypeInterface &derived_interface)
289{
290 /* Merge usages from all group input nodes. */
291 Array<DataRequirement> interface_requirements(tree.interface_inputs().size(),
293 for (const bNode *node : tree.group_input_nodes()) {
294 const Span<const bNodeSocket *> output_sockets = node->output_sockets();
295 for (const int i : output_sockets.index_range().drop_back(1)) {
296 const bNodeSocket &output = *output_sockets[i];
297 interface_requirements[i] = merge(
298 interface_requirements[i], calc_output_socket_requirement(output, input_requirements));
299 }
300 }
301
302 /* Build derived interface structure types from group input nodes. */
303 for (const int i : tree.interface_inputs().index_range()) {
304 const bNodeTreeInterfaceSocket &io_socket = *tree.interface_inputs()[i];
306 derived_interface.inputs[i] = StructureType(io_socket.structure_type);
307 continue;
308 }
309
310 const DataRequirement requirement = interface_requirements[i];
311 derived_interface.inputs[i] = data_requirement_to_auto_structure_type(requirement);
312 }
313}
314
316 const Span<DataRequirement> input_requirements,
317 const bits::BoundedBitSpan is_auto_structure_type,
318 MutableSpan<StructureType> structure_types)
319{
320 const Span<const bNodeSocket *> all_sockets = tree.all_sockets();
321 bits::foreach_1_index(is_auto_structure_type, [&](const int i) {
322 const bNodeSocket &socket = *all_sockets[i];
323 if (socket.is_input()) {
324 return;
325 }
326 const bNode &node = socket.owner_node();
327 if (node.is_group_input()) {
328 /* Group input nodes have special handling in #store_group_input_structure_types because
329 * corresponding sockets on all group input nodes should have the same structure type. */
330 return;
331 }
332
333 const DataRequirement requirement = calc_output_socket_requirement(socket, input_requirements);
334 structure_types[socket.index_in_tree()] = data_requirement_to_auto_structure_type(requirement);
335 });
336}
337
338enum class ZoneInOutChange {
339 None = 0,
340 In = (1 << 1),
341 Out = (1 << 2),
342};
344
346 const bNode &input_node,
347 const bNode &output_node,
348 MutableSpan<DataRequirement> input_requirements)
349{
351 for (const int i : output_node.output_sockets().index_range()) {
352 /* First input node output is Delta Time which does not appear in the output node outputs. */
353 const bNodeSocket &input_of_input_node = input_node.input_socket(i);
354 const bNodeSocket &output_of_output_node = output_node.output_socket(i);
355 const bNodeSocket &input_of_output_node = output_node.input_socket(i + 1);
356 const DataRequirement new_value = merge(
357 input_requirements[input_of_input_node.index_in_all_inputs()],
358 calc_output_socket_requirement(output_of_output_node, input_requirements));
359 if (input_requirements[input_of_input_node.index_in_all_inputs()] != new_value) {
360 input_requirements[input_of_input_node.index_in_all_inputs()] = new_value;
361 change |= ZoneInOutChange::In;
362 }
363 if (input_requirements[input_of_output_node.index_in_all_inputs()] != new_value) {
364 input_requirements[input_of_output_node.index_in_all_inputs()] = new_value;
365 change |= ZoneInOutChange::Out;
366 }
367 }
368 return change;
369}
370
372 const bNode &input_node,
373 const bNode &output_node,
374 MutableSpan<DataRequirement> input_requirements)
375{
377 for (const int i : output_node.output_sockets().index_range()) {
378 const bNodeSocket &input_of_input_node = input_node.input_socket(i + 1);
379 const bNodeSocket &output_of_output_node = output_node.output_socket(i);
380 const bNodeSocket &input_of_output_node = output_node.input_socket(i);
381 const DataRequirement new_value = merge(
382 input_requirements[input_of_input_node.index_in_all_inputs()],
383 calc_output_socket_requirement(output_of_output_node, input_requirements));
384 if (input_requirements[input_of_input_node.index_in_all_inputs()] != new_value) {
385 input_requirements[input_of_input_node.index_in_all_inputs()] = new_value;
386 change |= ZoneInOutChange::In;
387 }
388 if (input_requirements[input_of_output_node.index_in_all_inputs()] != new_value) {
389 input_requirements[input_of_output_node.index_in_all_inputs()] = new_value;
390 change |= ZoneInOutChange::Out;
391 }
392 }
393 return change;
394}
395
397 const bNode &node,
398 MutableSpan<DataRequirement> input_requirements)
399{
400 /* Sync field state between zone nodes and schedule another pass if necessary. */
401 switch (node.type_legacy) {
403 const auto &data = *static_cast<const NodeGeometrySimulationInput *>(node.storage);
404 if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
406 node, *output_node, input_requirements);
408 return true;
409 }
410 }
411 return false;
412 }
414 for (const bNode *input_node : tree.nodes_by_type("GeometryNodeSimulationInput")) {
415 const auto &data = *static_cast<const NodeGeometrySimulationInput *>(input_node->storage);
416 if (node.identifier == data.output_node_id) {
418 *input_node, node, input_requirements);
419 if ((change & ZoneInOutChange::In) != ZoneInOutChange::None) {
420 return true;
421 }
422 }
423 }
424 return false;
425 }
427 const auto &data = *static_cast<const NodeGeometryRepeatInput *>(node.storage);
428 if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
430 node, *output_node, input_requirements);
432 return true;
433 }
434 }
435 return false;
436 }
438 for (const bNode *input_node : tree.nodes_by_type("GeometryNodeRepeatInput")) {
439 const auto &data = *static_cast<const NodeGeometryRepeatInput *>(input_node->storage);
440 if (node.identifier == data.output_node_id) {
442 *input_node, node, input_requirements);
443 if ((change & ZoneInOutChange::In) != ZoneInOutChange::None) {
444 return true;
445 }
446 }
447 }
448 return false;
449 }
450 }
451
452 return false;
453}
454
456 const Span<nodes::StructureTypeInterface> node_interfaces,
457 MutableSpan<DataRequirement> input_requirements)
458{
459 while (true) {
460 bool need_update = false;
461
462 for (const bNode *node : tree.toposort_right_to_left()) {
463 const Span<const bNodeSocket *> input_sockets = node->input_sockets();
464 const Span<const bNodeSocket *> output_sockets = node->output_sockets();
465 const nodes::StructureTypeInterface &node_interface = node_interfaces[node->index()];
466
467 for (const int output : node_interface.outputs.index_range()) {
468 const bNodeSocket &output_socket = *output_sockets[output];
469 DataRequirement output_requirement = DataRequirement::None;
470 for (const bNodeSocket *socket : output_socket.directly_linked_sockets()) {
471 if (!socket->is_available()) {
472 continue;
473 }
474 output_requirement = merge(output_requirement,
475 input_requirements[socket->index_in_all_inputs()]);
476 }
477
478 switch (output_requirement) {
481 break;
482 }
484 /* If the output is a single, all inputs must be singles. */
485 for (const int input : node_interface.outputs[output].linked_inputs) {
486 const bNodeSocket &input_socket = *input_sockets[input];
487 input_requirements[input_socket.index_in_all_inputs()] = DataRequirement::Single;
488 }
489 break;
490 }
494 /* When a data requirement could be provided by multiple node inputs (i.e. only a
495 * single node input involved in a math operation has to be a volume grid for the
496 * output to be a grid), it's better to not propagate the data requirement than
497 * incorrectly saying that all of the inputs have it. */
498 Vector<int, 8> inputs_with_links;
499 for (const int input : node_interface.outputs[output].linked_inputs) {
500 const bNodeSocket &input_socket = *input_sockets[input];
501 if (input_requirements[input_socket.index_in_all_inputs()] ==
503 {
504 /* Inputs which require a single value can't get a different requirement. */
505 continue;
506 }
507 if (input_socket.is_directly_linked()) {
508 inputs_with_links.append(input_socket.index_in_all_inputs());
509 }
510 }
511 if (inputs_with_links.size() == 1) {
512 input_requirements[inputs_with_links.first()] = output_requirement;
513 }
514 else {
515 for (const int input : inputs_with_links) {
516 input_requirements[input] = DataRequirement::None;
517 }
518 }
519 break;
520 }
521 }
522 }
523
524 /* Find reverse dependencies and resolve conflicts, which may require another pass. */
525 if (propagate_zone_data_requirements(tree, *node, input_requirements)) {
526 need_update = true;
527 }
528 }
529
530 if (!need_update) {
531 break;
532 }
533 }
534}
535
536static StructureType left_to_right_merge(const StructureType a, const StructureType b)
537{
538 if (a == b) {
539 return a;
540 }
541 if (a == StructureType::Dynamic || b == StructureType::Dynamic) {
542 return StructureType::Dynamic;
543 }
544 if ((a == StructureType::Field && b == StructureType::Grid) ||
545 (a == StructureType::Grid && b == StructureType::Field))
546 {
547 return StructureType::Grid;
548 }
549 if ((a == StructureType::Single && b == StructureType::Field) ||
550 (a == StructureType::Field && b == StructureType::Single))
551 {
552 return StructureType::Field;
553 }
554 if ((a == StructureType::Single && b == StructureType::Grid) ||
555 (a == StructureType::Grid && b == StructureType::Single))
556 {
557 return StructureType::Grid;
558 }
559 if ((a == StructureType::Single && b == StructureType::List) ||
560 (a == StructureType::List && b == StructureType::Single))
561 {
562 return StructureType::List;
563 }
564 if ((a == StructureType::Field && b == StructureType::List) ||
565 (a == StructureType::List && b == StructureType::Field))
566 {
567 return StructureType::List;
568 }
569 /* Invalid combination. */
570 return a;
571}
572
574 const bNode &output_node,
575 MutableSpan<StructureType> structure_types)
576{
578 for (const int i : output_node.output_sockets().index_range()) {
579 /* First input node output is Delta Time which does not appear in the output node outputs. */
580 const bNodeSocket &input = input_node.output_socket(i + 1);
581 const bNodeSocket &output = output_node.output_socket(i);
582 const StructureType new_value = left_to_right_merge(structure_types[input.index_in_tree()],
583 structure_types[output.index_in_tree()]);
584 if (structure_types[input.index_in_tree()] != new_value) {
585 structure_types[input.index_in_tree()] = new_value;
586 change |= ZoneInOutChange::In;
587 }
588 if (structure_types[output.index_in_tree()] != new_value) {
589 structure_types[output.index_in_tree()] = new_value;
590 change |= ZoneInOutChange::Out;
591 }
592 }
593 return change;
594}
595
597 const bNode &output_node,
598 MutableSpan<StructureType> structure_types)
599{
601 for (const int i : output_node.output_sockets().index_range()) {
602 const bNodeSocket &input_of_input_node = input_node.output_socket(i + 1);
603 const bNodeSocket &output_of_output_node = output_node.output_socket(i);
604 const StructureType new_value = left_to_right_merge(
605 structure_types[input_of_input_node.index_in_tree()],
606 structure_types[output_of_output_node.index_in_tree()]);
607 if (structure_types[input_of_input_node.index_in_tree()] != new_value) {
608 structure_types[input_of_input_node.index_in_tree()] = new_value;
609 change |= ZoneInOutChange::In;
610 }
611 if (structure_types[output_of_output_node.index_in_tree()] != new_value) {
612 structure_types[output_of_output_node.index_in_tree()] = new_value;
613 change |= ZoneInOutChange::Out;
614 }
615 }
616 return change;
617}
618
620 const bNode &node,
621 MutableSpan<StructureType> structure_types)
622{
623 /* Sync field state between zone nodes and schedule another pass if necessary. */
624 switch (node.type_legacy) {
626 const auto &data = *static_cast<const NodeGeometrySimulationInput *>(node.storage);
627 if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
629 node, *output_node, structure_types);
631 return true;
632 }
633 }
634 return false;
635 }
637 for (const bNode *input_node : tree.nodes_by_type("GeometryNodeSimulationInput")) {
638 const auto &data = *static_cast<const NodeGeometrySimulationInput *>(input_node->storage);
639 if (node.identifier == data.output_node_id) {
641 *input_node, node, structure_types);
642 if ((change & ZoneInOutChange::In) != ZoneInOutChange::None) {
643 return true;
644 }
645 }
646 }
647 return false;
648 }
650 const auto &data = *static_cast<const NodeGeometryRepeatInput *>(node.storage);
651 if (const bNode *output_node = tree.node_by_id(data.output_node_id)) {
653 node, *output_node, structure_types);
655 return true;
656 }
657 }
658 return false;
659 }
661 for (const bNode *input_node : tree.nodes_by_type("GeometryNodeRepeatInput")) {
662 const auto &data = *static_cast<const NodeGeometryRepeatInput *>(input_node->storage);
663 if (node.identifier == data.output_node_id) {
665 *input_node, node, structure_types);
666 if ((change & ZoneInOutChange::In) != ZoneInOutChange::None) {
667 return true;
668 }
669 }
670 }
671 return false;
672 }
673 }
674
675 return false;
676}
677
679 const nodes::SocketDeclaration &declaration)
680{
682 return StructureType::Field;
683 }
684 return StructureType::Single;
685}
686
688 const Span<nodes::StructureTypeInterface> node_interfaces,
689 const Span<StructureType> group_input_structure_types,
690 const bits::BoundedBitSpan is_auto_structure_type,
691 MutableSpan<StructureType> structure_types)
692{
693 for (const bNodeSocket *input : tree.all_input_sockets()) {
694 if (input->owner_node().is_undefined()) {
695 continue;
696 }
697 if (!input->is_directly_linked()) {
698 if (const nodes::SocketDeclaration *declaration = input->runtime->declaration) {
699 structure_types[input->index_in_tree()] = get_unconnected_input_structure_type(
700 *declaration);
701 }
702 }
703 }
704
705 /* Outputs of these nodes have dynamic structure type but should start out as single values. */
706 for (const StringRefNull idname : {"GeometryNodeRepeatInput",
707 "GeometryNodeRepeatOutput",
708 "GeometryNodeSimulationInput",
709 "GeometryNodeSimulationOutput"})
710 {
711 for (const bNode *node : tree.nodes_by_type(idname)) {
712 for (const bNodeSocket *socket : node->output_sockets()) {
713 structure_types[socket->index_in_tree()] = StructureType::Single;
714 }
715 }
716 }
717
718 while (true) {
719 bool need_update = false;
720 for (const bNode *node : tree.toposort_left_to_right()) {
721 if (node->is_undefined()) {
722 continue;
723 }
724 const Span<const bNodeSocket *> input_sockets = node->input_sockets();
725 const Span<const bNodeSocket *> output_sockets = node->output_sockets();
726 if (node->is_group_input()) {
727 for (const int i : output_sockets.index_range().drop_back(1)) {
728 structure_types[output_sockets[i]->index_in_tree()] = group_input_structure_types[i];
729 }
730 continue;
731 }
732
733 for (const bNodeSocket *input : input_sockets) {
734 if (!input->is_available()) {
735 continue;
736 }
737
738 std::optional<StructureType> input_type;
739 for (const bNodeLink *link : input->directly_linked_links()) {
740 if (!link->is_used()) {
741 continue;
742 }
743 const StructureType new_type = structure_types[link->fromsock->index_in_tree()];
744 if (input_type) {
745 input_type = left_to_right_merge(*input_type, new_type);
746 }
747 else {
748 input_type = new_type;
749 }
750 }
751 if (input_type) {
752 structure_types[input->index_in_tree()] = *input_type;
753 }
754 }
755
756 const nodes::StructureTypeInterface &node_interface = node_interfaces[node->index()];
757
758 for (const int output_index : node_interface.outputs.index_range()) {
759 const bNodeSocket &output = *output_sockets[output_index];
760 if (!output.is_available() || !output.runtime->declaration) {
761 continue;
762 }
763 if (is_auto_structure_type[output.index_in_tree()]) {
764 /* Has been initialized in #store_auto_output_structure_types. */
765 continue;
766 }
767 const nodes::SocketDeclaration &declaration = *output.runtime->declaration;
768
769 std::optional<StructureType> output_type;
770 for (const int input_index : node_interface.outputs[output_index].linked_inputs) {
771 const bNodeSocket &input = node->input_socket(input_index);
772 if (!input.is_available()) {
773 continue;
774 }
775 const StructureType new_type = structure_types[input.index_in_tree()];
776 if (output_type) {
777 output_type = left_to_right_merge(*output_type, new_type);
778 }
779 else {
780 output_type = new_type;
781 }
782 }
783 structure_types[output.index_in_tree()] = output_type.value_or(declaration.structure_type);
784 }
785
786 if (propagate_zone_status(tree, *node, structure_types)) {
787 need_update = true;
788 }
789 }
790
791 if (!need_update) {
792 break;
793 }
794 }
795}
796
798 const bNodeSocket &group_output, const Span<nodes::StructureTypeInterface> interface_by_node)
799{
800 /* Use a Set instead of an array indexed by socket because we may only look at a few sockets. */
801 Set<const bNodeSocket *> handled_sockets;
802 Stack<const bNodeSocket *> sockets_to_check;
803
804 handled_sockets.add(&group_output);
805 sockets_to_check.push(&group_output);
806
807 Vector<int> group_inputs;
808
809 while (!sockets_to_check.is_empty()) {
810 const bNodeSocket *input_socket = sockets_to_check.pop();
811 if (!input_socket->is_directly_linked()) {
812 continue;
813 }
814
815 for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) {
816 const bNode &origin_node = origin_socket->owner_node();
817 if (origin_node.is_group_input()) {
818 group_inputs.append_non_duplicates(origin_socket->index());
819 continue;
820 }
821
822 const nodes::StructureTypeInterface &node_interface = interface_by_node[origin_node.index()];
823 for (const int input_index : node_interface.outputs[origin_socket->index()].linked_inputs) {
824 const bNodeSocket &input = origin_node.input_socket(input_index);
825 if (!input.is_available()) {
826 continue;
827 }
828 if (handled_sockets.add(&input)) {
829 sockets_to_check.push(&input);
830 }
831 }
832 }
833 }
834
835 return group_inputs;
836}
837
839 const bNodeTree &tree,
840 const Span<nodes::StructureTypeInterface> interface_by_node,
841 const Span<StructureType> structure_types,
843{
844 const bNode *group_output_node = tree.group_output_node();
845 if (!group_output_node) {
847 output.type = StructureType::Dynamic;
848 }
849 return;
850 }
851
852 const Span<const bNodeTreeInterfaceSocket *> interface_outputs = tree.interface_outputs();
853 const Span<const bNodeSocket *> sockets = group_output_node->input_sockets().drop_back(1);
854 for (const int i : sockets.index_range()) {
855 if (interface_outputs[i]->structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
856 interface.outputs[i] = {StructureType(interface_outputs[i]->structure_type), {}};
857 continue;
858 }
859 /* Update derived interface output structure types from output node socket usages. */
860 interface.outputs[i].type = structure_types[sockets[i]->index_in_tree()];
861 if (interface.outputs[i].type == StructureType::Dynamic) {
862 const Vector<int> linked_inputs = find_dynamic_output_linked_inputs(*sockets[i],
863 interface_by_node);
864 interface.outputs[i] = {StructureType::Dynamic, linked_inputs.as_span()};
865 }
866 }
867}
868
873
875{
876 tree.ensure_topology_cache();
877 tree.ensure_interface_cache();
878
880 result.socket_structure_types = Array<StructureType>(tree.all_sockets().size(),
881 StructureType::Dynamic);
882
883 result.group_interface.inputs.reinitialize(tree.interface_inputs().size());
884 result.group_interface.outputs.reinitialize(tree.interface_outputs().size());
885 if (tree.has_available_link_cycle()) {
886 result.group_interface.inputs.fill(StructureType::Dynamic);
887 result.group_interface.outputs.fill({StructureType::Dynamic, {}});
888 return result;
889 }
890
892 bits::BitVector<> is_auto_structure_type(tree.all_sockets().size(), false);
893
894 Array<DataRequirement> data_requirements(tree.all_input_sockets().size());
895
896 find_auto_structure_type_sockets(tree, is_auto_structure_type);
897 init_input_requirements(tree, is_auto_structure_type, data_requirements);
898 propagate_right_to_left(tree, node_interfaces, data_requirements);
899 store_group_input_structure_types(tree, data_requirements, result.group_interface);
901 tree, data_requirements, is_auto_structure_type, result.socket_structure_types);
903 node_interfaces,
904 result.group_interface.inputs,
905 is_auto_structure_type,
906 result.socket_structure_types);
908 tree, node_interfaces, result.socket_structure_types, result.group_interface);
909
910 /* Ensure that the structure type is never invalid. */
911 for (const int i : tree.all_sockets().index_range()) {
912 const bNodeSocket &socket = *tree.all_sockets()[i];
914 result.socket_structure_types[i] = StructureType::Single;
915 }
916 }
917
918 return result;
919}
920
922{
924 for (const int i : tree.all_sockets().index_range()) {
925 const bNodeSocket &socket = *tree.all_sockets()[i];
926 socket.runtime->inferred_structure_type = result.socket_structure_types[i];
927 }
928 if (tree.runtime->structure_type_interface &&
929 *tree.runtime->structure_type_interface == result.group_interface)
930 {
931 return false;
932 }
933 tree.runtime->structure_type_interface = std::make_unique<nodes::StructureTypeInterface>(
934 std::move(result.group_interface));
935 return true;
936}
937
938} // namespace blender::bke::node_structure_type_inferencing
#define GEO_NODE_SIMULATION_OUTPUT
#define NODE_CLOSURE_OUTPUT
#define GEO_NODE_REPEAT_OUTPUT
#define GEO_NODE_REPEAT_INPUT
#define GEO_NODE_SIMULATION_INPUT
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define ENUM_OPERATORS(_type, _max)
@ NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO
eNodeSocketDatatype
BMesh const char void * data
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
constexpr IndexRange drop_back(int64_t n) const
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
int64_t size() const
void append(const T &value)
void append_non_duplicates(const T &value)
Span< T > as_span() const
const T & first() const
MutableBitSpan slice(const IndexRange range) const
const bNode * get_corresponding_output(const bNodeTree &tree, const bNode &input_bnode) const
OutputSocketFieldType field_type() const
KDTree_3d * tree
#define input
#define output
void fill_index_range(MutableSpan< T > span, const T start=0)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
static void store_group_input_structure_types(const bNodeTree &tree, const Span< DataRequirement > input_requirements, nodes::StructureTypeInterface &derived_interface)
static void store_auto_output_structure_types(const bNodeTree &tree, const Span< DataRequirement > input_requirements, const bits::BoundedBitSpan is_auto_structure_type, MutableSpan< StructureType > structure_types)
static void init_input_requirements(const bNodeTree &tree, const bits::BoundedBitSpan is_auto_structure_type, MutableSpan< DataRequirement > input_requirements)
static void propagate_right_to_left(const bNodeTree &tree, const Span< nodes::StructureTypeInterface > node_interfaces, MutableSpan< DataRequirement > input_requirements)
static DataRequirement merge(const DataRequirement a, const DataRequirement b)
static StructureType data_requirement_to_auto_structure_type(const DataRequirement requirement)
static StructureType left_to_right_merge(const StructureType a, const StructureType b)
static ZoneInOutChange simulation_zone_requirements_propagate(const bNode &input_node, const bNode &output_node, MutableSpan< DataRequirement > input_requirements)
static bool propagate_zone_status(const bNodeTree &tree, const bNode &node, MutableSpan< StructureType > structure_types)
static ZoneInOutChange simulation_zone_status_propagate(const bNode &input_node, const bNode &output_node, MutableSpan< StructureType > structure_types)
static StructureTypeInferenceResult calc_structure_type_interface(const bNodeTree &tree)
static ZoneInOutChange repeat_zone_requirements_propagate(const bNode &input_node, const bNode &output_node, MutableSpan< DataRequirement > input_requirements)
static DataRequirement calc_output_socket_requirement(const bNodeSocket &output_socket, const Span< DataRequirement > input_requirements)
static Vector< int > find_dynamic_output_linked_inputs(const bNodeSocket &group_output, const Span< nodes::StructureTypeInterface > interface_by_node)
static nodes::StructureTypeInterface calc_node_interface(const bNode &node)
static void propagate_left_to_right(const bNodeTree &tree, const Span< nodes::StructureTypeInterface > node_interfaces, const Span< StructureType > group_input_structure_types, const bits::BoundedBitSpan is_auto_structure_type, MutableSpan< StructureType > structure_types)
static bool propagate_zone_data_requirements(const bNodeTree &tree, const bNode &node, MutableSpan< DataRequirement > input_requirements)
static ZoneInOutChange repeat_zone_status_propagate(const bNode &input_node, const bNode &output_node, MutableSpan< StructureType > structure_types)
static StructureType get_unconnected_input_structure_type(const nodes::SocketDeclaration &declaration)
static void store_group_output_structure_types(const bNodeTree &tree, const Span< nodes::StructureTypeInterface > interface_by_node, const Span< StructureType > structure_types, nodes::StructureTypeInterface &interface)
static Array< nodes::StructureTypeInterface > calc_node_interfaces(const bNodeTree &tree)
static void find_auto_structure_type_sockets(const bNodeTree &tree, bits::MutableBoundedBitSpan is_auto_structure_type)
const bNodeZoneType * zone_type_by_node_type(const int node_type)
bool socket_type_always_single(const eNodeSocketDatatype socket_type)
bNodeSocketRuntimeHandle * runtime
int16_t type_legacy
void * storage
int32_t identifier
i
Definition text_draw.cc:230