Blender V5.0
node_tree_reference_lifetimes.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Foundation
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <iostream>
6
7#include <fmt/format.h>
8
10#include "BKE_node_runtime.hh"
14
16#include "BLI_bit_span_ops.hh"
17
19#include "NOD_socket.hh"
20
21#include "BLI_resource_scope.hh"
22
24
25using bits::BitInt;
26using nodes::NodeDeclaration;
27namespace aal = nodes::aal;
28
29std::ostream &operator<<(std::ostream &stream, const ReferenceSetInfo &info)
30{
31 switch (info.type) {
33 stream << "Group Output Data: " << info.index;
34 break;
36 stream << "Group Input Reference: " << info.index;
37 break;
39 stream << "Local: " << info.socket->name;
40 break;
42 stream << "Closure Input Reference: " << info.socket->name;
43 break;
45 stream << "Closure Output Data: " << info.socket->name;
46 break;
47 }
48 stream << " (";
49 for (const bNodeSocket *socket : info.potential_data_origins) {
50 stream << socket->name << ", ";
51 }
52 stream << ")";
53 return stream;
54}
55
56static bool socket_may_have_reference(const bNodeSocket &socket)
57{
58 return socket.may_be_field() || ELEM(socket.type, SOCK_BUNDLE, SOCK_CLOSURE);
59}
60
63 const BoundedBitSpan mask)
64{
66 return false;
67 }
70 return true;
71}
72
74{
75 if (bits::spans_equal(a, b)) {
76 return false;
77 }
78 a |= b;
79 b |= a;
80 return true;
81}
82
84{
85 return nodes::socket_type_supports_fields(socket_type) ||
86 ELEM(socket_type, SOCK_BUNDLE, SOCK_CLOSURE);
87}
88
90{
91 return ELEM(socket_type, SOCK_GEOMETRY, SOCK_BUNDLE, SOCK_CLOSURE);
92}
93
95 const bNode &node)
96{
97 if (!zones) {
98 return nullptr;
99 }
100 const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
101 if (!zone) {
102 return nullptr;
103 }
104 if (!zone->input_node_id || !zone->output_node_id) {
105 return nullptr;
106 }
107 return zone;
108}
109
111 ResourceScope &scope)
112{
113 Array<const aal::RelationsInNode *> relations_by_node(tree.all_nodes().size());
114 for (const bNode *node : tree.all_nodes()) {
115 const aal::RelationsInNode *node_relations = nullptr;
116 switch (node->type_legacy) {
119 case GEO_NODE_BAKE: {
120 /* The relations of these nodes depend on field evaluation to avoid unnecessary
121 * relations, but besides that they don't need special handling. */
122 aal::RelationsInNode &relations = scope.construct<aal::RelationsInNode>();
123 {
124 /* Add eval relations. */
125 int prev_geometry_index = -1;
126 for (const int i : node->input_sockets().index_range()) {
127 const bNodeSocket &socket = node->input_socket(i);
128 if (socket.type == SOCK_GEOMETRY) {
129 prev_geometry_index = i;
130 continue;
131 }
132 if (prev_geometry_index == -1) {
133 continue;
134 }
135 if (socket_may_have_reference(socket)) {
136 relations.eval_relations.append({i, prev_geometry_index});
137 }
138 }
139 }
140 {
141 /* Add available relations. */
142 int prev_geometry_index = -1;
143 for (const int i : node->output_sockets().index_range()) {
144 const bNodeSocket &socket = node->output_socket(i);
145 if (socket.type == SOCK_GEOMETRY) {
146 prev_geometry_index = i;
147 }
148 if (prev_geometry_index == -1) {
149 continue;
150 }
151 if (socket_may_have_reference(socket)) {
152 relations.available_relations.append({i, prev_geometry_index});
153 }
154 }
155 }
156 node_relations = &relations;
157 break;
158 }
161 aal::RelationsInNode &relations = scope.construct<aal::RelationsInNode>();
162 for (const bNodeSocket *socket : node->output_sockets()) {
164 for (const bNodeSocket *other_output : node->output_sockets()) {
165 if (socket_may_have_reference(*other_output)) {
166 relations.available_relations.append({other_output->index(), socket->index()});
167 }
168 }
169 }
170 }
171 for (const bNodeSocket *socket : node->input_sockets()) {
173 for (const bNodeSocket *other_input : node->input_sockets()) {
174 if (socket_may_have_reference(*other_input)) {
175 relations.eval_relations.append({other_input->index(), socket->index()});
176 }
177 }
178 }
179 }
180 /* Only create propagate and reference relations for the input node. The output node
181 * needs special handling because attributes created inside of the zone are not directly
182 * referenced on the outside. */
183 if (node->type_legacy == GEO_NODE_REPEAT_INPUT) {
184 const int input_items_start = 1;
185 const int output_items_start = 1;
186 const int items_num = node->output_sockets().size() - 1 - output_items_start;
187 for (const int i : IndexRange(items_num)) {
188 const int input_index = input_items_start + i;
189 const int output_index = output_items_start + i;
190 const bNodeSocket &input_socket = node->input_socket(input_index);
192 relations.propagate_relations.append({input_index, output_index});
193 }
194 else if (socket_may_have_reference(input_socket)) {
195 relations.reference_relations.append({input_index, output_index});
196 }
197 }
198 }
199 node_relations = &relations;
200 break;
201 }
202 case NODE_REROUTE: {
203 static const aal::RelationsInNode reroute_relations = []() {
204 aal::RelationsInNode relations;
205 relations.propagate_relations.append({0, 0});
206 relations.reference_relations.append({0, 0});
207 return relations;
208 }();
209 node_relations = &reroute_relations;
210 break;
211 }
212 case NODE_GROUP:
213 case NODE_CUSTOM_GROUP: {
214 if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id)) {
215 if (group->runtime->reference_lifetimes_info) {
216 node_relations = &group->runtime->reference_lifetimes_info->tree_relations;
217 }
218 }
219 break;
220 }
221 default: {
222 if (const NodeDeclaration *node_decl = node->declaration()) {
223 node_relations = node_decl->anonymous_attribute_relations();
224 }
225 break;
226 }
227 }
228 relations_by_node[node->index()] = node_relations;
229 }
230 return relations_by_node;
231}
232
234 const bNodeTree &tree,
235 const Span<const aal::RelationsInNode *> &relations_by_node,
236 Vector<int> &r_group_output_reference_sets,
237 MultiValueMap<const bNodeTreeZone *, int> &r_output_set_sources_by_closure_zone)
238{
239 Vector<ReferenceSetInfo> reference_sets;
240 const Span<const bNodeTreeInterfaceSocket *> interface_inputs = tree.interface_inputs();
241 const Span<const bNodeTreeInterfaceSocket *> interface_outputs = tree.interface_outputs();
242
243 /* Handle references coming from field inputs. */
244 for (const int input_i : interface_inputs.index_range()) {
245 const bNodeTreeInterfaceSocket &interface_input = *interface_inputs[input_i];
246 const bNodeSocketType *stype = interface_input.socket_typeinfo();
247 const eNodeSocketDatatype socket_type = stype ? stype->type : SOCK_CUSTOM;
248 if (can_contain_reference(socket_type)) {
249 reference_sets.append({ReferenceSetType::GroupInputReferenceSet, input_i});
250 }
251 }
252 /* Handle references required by output geometries. */
253 for (const int output_i : interface_outputs.index_range()) {
254 const bNodeTreeInterfaceSocket &interface_output = *interface_outputs[output_i];
255 const bNodeSocketType *stype = interface_output.socket_typeinfo();
256 const eNodeSocketDatatype socket_type = stype ? stype->type : SOCK_CUSTOM;
257 if (can_contain_referenced_data(socket_type)) {
258 r_group_output_reference_sets.append(
259 reference_sets.append_and_get_index({ReferenceSetType::GroupOutputData, output_i}));
260 }
261 }
262 /* All references referenced by the sources found so far can exist on all geometry inputs. */
263 for (const int input_i : interface_inputs.index_range()) {
264 const bNodeTreeInterfaceSocket &interface_input = *interface_inputs[input_i];
265 const bNodeSocketType *stype = interface_input.socket_typeinfo();
266 const eNodeSocketDatatype socket_type = stype ? stype->type : SOCK_CUSTOM;
267 if (can_contain_referenced_data(socket_type)) {
268 for (const bNode *node : tree.group_input_nodes()) {
269 const bNodeSocket &socket = node->output_socket(input_i);
270 for (ReferenceSetInfo &source : reference_sets) {
271 source.potential_data_origins.append(&socket);
272 }
273 }
274 }
275 }
276 /* Handle references created by nodes in the current tree. */
277 for (const bNode *node : tree.all_nodes()) {
278 if (node->is_muted()) {
279 continue;
280 }
281 if (const aal::RelationsInNode *relations = relations_by_node[node->index()]) {
282 for (const aal::AvailableRelation &relation : relations->available_relations) {
283 const bNodeSocket &data_socket = node->output_socket(relation.geometry_output);
284 const bNodeSocket &reference_socket = node->output_socket(relation.field_output);
285 if (!reference_socket.is_available() || !reference_socket.is_available()) {
286 continue;
287 }
288 if (!reference_socket.is_directly_linked() || !data_socket.is_directly_linked()) {
289 continue;
290 }
291 reference_sets.append({ReferenceSetType::LocalReferenceSet, &reference_socket});
292 reference_sets.last().potential_data_origins.append(&data_socket);
293 }
294 }
295 }
296 /* Each output of the Evaluate Closure node may reference data in any other output. We can't know
297 * exactly what references what here. */
298 for (const bNode *node : tree.nodes_by_type("NodeEvaluateClosure")) {
299 const auto &storage = *static_cast<NodeEvaluateClosure *>(node->storage);
300 Vector<const bNodeSocket *> reference_outputs;
301 for (const int i : IndexRange(storage.output_items.items_num)) {
302 const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
304 reference_outputs.append(&node->output_socket(i));
305 }
306 }
307 if (!reference_outputs.is_empty()) {
308 for (const int i : IndexRange(storage.output_items.items_num)) {
309 const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
311 reference_sets.append({ReferenceSetType::LocalReferenceSet, &node->output_socket(i)});
312 reference_sets.last().potential_data_origins.extend(reference_outputs);
313 }
314 }
315 }
316 }
317
318 const bNodeTreeZones *zones = tree.zones();
319 if (!zones) {
320 return reference_sets;
321 }
322 for (const bNodeTreeZone *zone : zones->zones) {
323 const bNode &input_node = *zone->input_node();
324 const bNode &output_node = *zone->output_node();
325 if (output_node.type_legacy != NODE_CLOSURE_OUTPUT) {
326 continue;
327 }
328 const auto &storage = *static_cast<const NodeClosureOutput *>(output_node.storage);
329 const int old_reference_sets_count = reference_sets.size();
330 /* Handle references coming from field inputs in the closure. */
331 for (const int input_i : IndexRange(storage.input_items.items_num)) {
332 const bNodeSocket &socket = input_node.output_socket(input_i);
334 reference_sets.append({ReferenceSetType::ClosureInputReferenceSet, &socket});
335 }
336 }
337 /* Handle references required by output geometries in the closure. */
338 for (const int output_i : IndexRange(storage.output_items.items_num)) {
339 const bNodeSocket &socket = output_node.input_socket(output_i);
341 r_output_set_sources_by_closure_zone.add(
342 zone,
343 reference_sets.append_and_get_index({ReferenceSetType::ClosureOutputData, &socket}));
344 }
345 }
346 /* All references referenced passed into this zone may exist on the geometry inputs. */
347 MutableSpan<ReferenceSetInfo> new_reference_sets = reference_sets.as_mutable_span().drop_front(
348 old_reference_sets_count);
349 for (const int input_i : IndexRange(storage.input_items.items_num)) {
350 const bNodeSocket &socket = input_node.output_socket(input_i);
352 for (ReferenceSetInfo &source : new_reference_sets) {
353 source.potential_data_origins.append(&socket);
354 }
355 }
356 }
357 }
358 return reference_sets;
359}
360
362 const Span<ReferenceSetInfo> reference_sets,
363 BitGroupVector<> &r_potential_data_by_socket,
364 BitGroupVector<> &r_potential_reference_by_socket)
365{
366 for (const int reference_set_i : reference_sets.index_range()) {
367 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
368 for (const bNodeSocket *socket : reference_set.potential_data_origins) {
369 r_potential_data_by_socket[socket->index_in_tree()][reference_set_i].set();
370 }
371 switch (reference_set.type) {
374 r_potential_reference_by_socket[reference_set.socket->index_in_tree()][reference_set_i]
375 .set();
376 break;
377 }
379 for (const bNode *node : tree.group_input_nodes()) {
380 const bNodeSocket &socket = node->output_socket(reference_set.index);
381 r_potential_reference_by_socket[socket.index_in_tree()][reference_set_i].set();
382 }
383 break;
384 }
387 /* Nothing to do. */
388 break;
389 }
390 }
391 }
392}
393
395 const bNodeTreeZone &zone, const Span<const BitGroupVector<> *> sources)
396{
397 BitVector<> found(sources.first()->group_size(), false);
398 /* Gather references that are passed into the zone from the outside, either through the input
399 * node or border links. */
400 for (const bNodeSocket *socket : zone.input_node()->input_sockets()) {
401 const int src = socket->index_in_tree();
402 for (const BitGroupVector<> *source : sources) {
403 found |= (*source)[src];
404 }
405 }
406 for (const bNodeLink *link : zone.border_links) {
407 const int src = link->fromsock->index_in_tree();
408 for (const BitGroupVector<> *source : sources) {
409 found |= (*source)[src];
410 }
411 }
412 return found;
413}
414
419 const Span<const aal::RelationsInNode *> &relations_by_node,
420 BitGroupVector<> &r_potential_data_by_socket,
421 BitGroupVector<> &r_potential_reference_by_socket)
422{
423 bool needs_extra_pass = false;
424 const bNodeTreeZones *zones = tree.zones();
425 for (const bNode *node : tree.toposort_left_to_right()) {
426 for (const bNodeSocket *socket : node->input_sockets()) {
427 if (!socket->is_available()) {
428 continue;
429 }
430 const int dst_index = socket->index_in_tree();
431 for (const bNodeLink *link : socket->directly_linked_links()) {
432 if (!link->is_used()) {
433 continue;
434 }
435 const int src_index = link->fromsock->index_in_tree();
436 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
437 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
438 }
439 }
440 if (node->is_muted()) {
441 for (const bNodeLink &link : node->internal_links()) {
442 const bNodeSocket &input_socket = *link.fromsock;
443 const bNodeSocket &output_socket = *link.tosock;
444 if (!input_socket.is_available() || !output_socket.is_available()) {
445 continue;
446 }
447 const int src_index = input_socket.index_in_tree();
448 const int dst_index = output_socket.index_in_tree();
449 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
450 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
451 }
452 continue;
453 }
454 if (const aal::RelationsInNode *relations = relations_by_node[node->index()]) {
455 /* Propagate references. */
456 for (const aal::ReferenceRelation &relation : relations->reference_relations) {
457 const bNodeSocket &from_socket = node->input_socket(relation.from_field_input);
458 const bNodeSocket &to_socket = node->output_socket(relation.to_field_output);
459 if (!from_socket.is_available() || !to_socket.is_available()) {
460 continue;
461 }
462 const int src_index = from_socket.index_in_tree();
463 const int dst_index = to_socket.index_in_tree();
464 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
465 }
466 /* Propagate data. */
467 for (const aal::PropagateRelation &relation : relations->propagate_relations) {
468 const bNodeSocket &from_socket = node->input_socket(relation.from_geometry_input);
469 const bNodeSocket &to_socket = node->output_socket(relation.to_geometry_output);
470 if (!from_socket.is_available() || !to_socket.is_available()) {
471 continue;
472 }
473 const int src_index = from_socket.index_in_tree();
474 const int dst_index = to_socket.index_in_tree();
475 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
476 }
477 }
478 switch (node->type_legacy) {
479 /* This zone needs additional special handling because attributes from the input geometry
480 * are propagated to the output node. */
482 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
483 if (!zone) {
484 break;
485 }
486 const bNode *input_node = zone->input_node();
487 const bNode *output_node = node;
488 const auto *storage = static_cast<const NodeGeometryForeachGeometryElementOutput *>(
489 node->storage);
490 const int src_index = input_node->input_socket(0).index_in_tree();
491 for (const bNodeSocket *output_socket : output_node->output_sockets()) {
492 if (output_socket->type == SOCK_GEOMETRY) {
493 const int dst_index = output_socket->index_in_tree();
494 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
495 }
496 }
497
498 /* Propagate references from the inside to the outside. Like in the repeat zone, new
499 * references created in the zone stay local inside the zone and are not propagated to the
500 * outside. Instead, the foreach-element output node creates new references. */
501 const BitVector<> outside_references = get_references_coming_from_outside_zone(
502 *zone, {&r_potential_data_by_socket, &r_potential_reference_by_socket});
503 for (const int item_i : IndexRange(storage->generation_items.items_num)) {
504 const int src_index =
505 node->input_socket(storage->main_items.items_num + item_i).index_in_tree();
506 const int dst_index =
507 node->output_socket(1 + storage->main_items.items_num + item_i).index_in_tree();
508 bits::inplace_or_masked(r_potential_data_by_socket[dst_index],
509 outside_references,
510 r_potential_data_by_socket[src_index]);
511 bits::inplace_or_masked(r_potential_reference_by_socket[dst_index],
512 outside_references,
513 r_potential_reference_by_socket[src_index]);
514 }
515 break;
516 }
517 case NODE_CLOSURE_INPUT: {
518 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
519 if (!zone) {
520 break;
521 }
522 const bNode &input_node = *zone->input_node();
523 /* Data referenced by border links may also be passed into the closure as input. */
524 const BitVector<> outside_references = get_references_coming_from_outside_zone(
525 *zone, {&r_potential_data_by_socket, &r_potential_reference_by_socket});
526 for (const int i : node->output_sockets().index_range()) {
527 const int dst_index = input_node.output_socket(i).index_in_tree();
528 r_potential_data_by_socket[dst_index] |= outside_references;
529 r_potential_reference_by_socket[dst_index] |= outside_references;
530 }
531 break;
532 }
533 case NODE_CLOSURE_OUTPUT: {
534 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
535 if (!zone) {
536 break;
537 }
538 const bNode &output_node = *zone->output_node();
539 /* References passed through border links are referenced by the closure. */
540 const BitVector<> passed_in_references = get_references_coming_from_outside_zone(
541 *zone, {&r_potential_reference_by_socket});
543 *zone, {&r_potential_data_by_socket});
544 const int dst_index = output_node.output_socket(0).index_in_tree();
545 for ([[maybe_unused]] const int i : node->input_sockets().index_range()) {
546 r_potential_data_by_socket[dst_index] |= passed_in_data;
547 r_potential_reference_by_socket[dst_index] |= passed_in_references;
548 }
549 break;
550 }
552 BitVector<> potential_input_references(r_potential_reference_by_socket.group_size());
553 BitVector<> potential_input_data(r_potential_data_by_socket.group_size());
554 /* Gather all references and data from all inputs, including the once on the closure input.
555 * The output may reference any of those. */
556 for (const bNodeSocket *socket : node->input_sockets()) {
557 const int src_index = socket->index_in_tree();
558 potential_input_references |= r_potential_reference_by_socket[src_index];
559 potential_input_data |= r_potential_data_by_socket[src_index];
560 }
561 for (const bNodeSocket *out_socket : node->output_sockets()) {
562 const int dst_index = out_socket->index_in_tree();
563 r_potential_reference_by_socket[dst_index] |= potential_input_references;
564 r_potential_data_by_socket[dst_index] |= potential_input_data;
565 }
566 break;
567 }
569 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
570 if (!zone) {
571 break;
572 }
573 const bNode &input_node = *zone->input_node();
574 const bNode &output_node = *zone->output_node();
575 const int items_num = output_node.output_sockets().size() - 1;
576
577 /* Handle data propagation in the case when the iteration count is zero. */
578 for (const int i : IndexRange(items_num)) {
579 const int src_index = input_node.input_socket(i + 1).index_in_tree();
580 const int dst_index = output_node.output_socket(i).index_in_tree();
581 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
582 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
583 }
584
585 const BitVector<> outside_references = get_references_coming_from_outside_zone(
586 *zone, {&r_potential_data_by_socket, &r_potential_reference_by_socket});
587
588 /* Propagate within output node. */
589 for (const int i : IndexRange(items_num)) {
590 const int src_index = output_node.input_socket(i).index_in_tree();
591 const int dst_index = output_node.output_socket(i).index_in_tree();
592 bits::inplace_or_masked(r_potential_data_by_socket[dst_index],
593 outside_references,
594 r_potential_data_by_socket[src_index]);
595 bits::inplace_or_masked(r_potential_reference_by_socket[dst_index],
596 outside_references,
597 r_potential_reference_by_socket[src_index]);
598 }
599
600 /* Ensure that references and data on the input and output node are equal. Since this may
601 * propagate information backwards, an additional pass can be necessary. */
602 for (const int i : IndexRange(items_num)) {
603 const bNodeSocket &body_input_socket = input_node.output_socket(i + 1);
604 const bNodeSocket &body_output_socket = output_node.input_socket(i);
605 const int in_index = body_output_socket.index_in_tree();
606 const int out_index = body_input_socket.index_in_tree();
607 needs_extra_pass |= or_into_each_other_masked(r_potential_data_by_socket[in_index],
608 r_potential_data_by_socket[out_index],
609 outside_references);
610 needs_extra_pass |= or_into_each_other_masked(r_potential_reference_by_socket[in_index],
611 r_potential_reference_by_socket[out_index],
612 outside_references);
613 }
614 break;
615 }
616 }
617 }
618 return needs_extra_pass;
619}
620
622 const bNodeTree &tree,
623 const Span<ReferenceSetInfo> reference_sets,
624 const Span<int> group_output_set_sources,
625 const BitGroupVector<> &potential_data_by_socket,
626 const BitGroupVector<> &potential_reference_by_socket,
627 BitGroupVector<> &r_required_data_by_socket)
628{
629 if (const bNode *group_output_node = tree.group_output_node()) {
630 const Span<const bNodeSocket *> sockets = group_output_node->input_sockets().drop_back(1);
631 for (const int reference_set_i : group_output_set_sources) {
632 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
634 const int index = sockets[reference_set.index]->index_in_tree();
635 r_required_data_by_socket[index][reference_set_i].set();
636 }
637 BitVector<> potential_output_references(reference_sets.size(), false);
638 for (const bNodeSocket *socket : sockets) {
639 potential_output_references |= potential_reference_by_socket[socket->index_in_tree()];
640 }
641 for (const bNodeSocket *socket : sockets) {
643 continue;
644 }
645 const int index = socket->index_in_tree();
646 r_required_data_by_socket[index] |= potential_output_references;
647 /* Make sure that only available data is also required. This is enforced in the end anyway,
648 * but may reduce some unnecessary work. */
649 r_required_data_by_socket[index] &= potential_data_by_socket[index];
650 }
651 }
652}
653
655 const bNodeTree &tree,
656 const Span<ReferenceSetInfo> reference_sets,
657 MultiValueMap<const bNodeTreeZone *, int> &output_set_sources_by_closure_zone,
658 const BitGroupVector<> &potential_data_by_socket,
659 const BitGroupVector<> &potential_reference_by_socket,
660 BitGroupVector<> &r_required_data_by_socket)
661{
662 const bNodeTreeZones *zones = tree.zones();
663 if (!zones) {
664 return;
665 }
666 for (const bNodeTreeZone *zone : zones->zones) {
667 if (!zone->input_node_id || !zone->output_node_id) {
668 continue;
669 }
670 const bNode &output_node = *zone->output_node();
671 if (output_node.type_legacy != NODE_CLOSURE_OUTPUT) {
672 continue;
673 }
674 const Span<int> closure_output_set_sources = output_set_sources_by_closure_zone.lookup(zone);
675 for (const int reference_set_i : closure_output_set_sources) {
676 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
678 r_required_data_by_socket[reference_set.socket->index_in_tree()][reference_set_i].set();
679 }
680 BitVector<> potential_output_references(reference_sets.size(), false);
681 const Span<const bNodeSocket *> sockets = output_node.input_sockets().drop_back(1);
682 for (const bNodeSocket *socket : sockets) {
683 potential_output_references |= potential_reference_by_socket[socket->index_in_tree()];
684 }
685 for (const bNodeSocket *socket : sockets) {
687 continue;
688 }
689 const int index = socket->index_in_tree();
690 r_required_data_by_socket[index] |= potential_output_references;
691 /* Make sure that only available data is also required. This is enforced in the end anyway,
692 * but may reduce some unnecessary work. */
693 r_required_data_by_socket[index] &= potential_data_by_socket[index];
694 }
695 }
696}
697
699 const bNodeTree &tree,
700 const Span<ReferenceSetInfo> reference_sets,
701 const Span<int> group_output_set_sources,
702 MultiValueMap<const bNodeTreeZone *, int> &output_set_sources_by_closure_zone,
703 const BitGroupVector<> &potential_data_by_socket,
704 const BitGroupVector<> &potential_reference_by_socket,
705 BitGroupVector<> &r_required_data_by_socket)
706{
708 reference_sets,
709 group_output_set_sources,
710 potential_data_by_socket,
711 potential_reference_by_socket,
712 r_required_data_by_socket);
714 reference_sets,
715 output_set_sources_by_closure_zone,
716 potential_data_by_socket,
717 potential_reference_by_socket,
718 r_required_data_by_socket);
719}
720
722 const Span<const aal::RelationsInNode *> &relations_by_node,
723 const BitGroupVector<> &potential_reference_by_socket,
724 BitGroupVector<> &r_required_data_by_socket)
725{
726 bool needs_extra_pass = false;
727 const bNodeTreeZones *zones = tree.zones();
728 for (const bNode *node : tree.toposort_right_to_left()) {
729 for (const bNodeSocket *socket : node->output_sockets()) {
730 if (!socket->is_available()) {
731 continue;
732 }
733 const int dst_index = socket->index_in_tree();
734 for (const bNodeLink *link : socket->directly_linked_links()) {
735 if (!link->is_used()) {
736 continue;
737 }
738 const int src_index = link->tosock->index_in_tree();
739 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
740 }
741 }
742 if (node->is_muted()) {
743 for (const bNodeLink &link : node->internal_links()) {
744 const bNodeSocket &input_socket = *link.fromsock;
745 const bNodeSocket &output_socket = *link.tosock;
746 if (!input_socket.is_available() || !output_socket.is_available()) {
747 continue;
748 }
749 const int dst_index = input_socket.index_in_tree();
750 const int src_index = output_socket.index_in_tree();
751 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
752 }
753 continue;
754 }
755 if (const aal::RelationsInNode *relations = relations_by_node[node->index()]) {
756 for (const aal::PropagateRelation &relation : relations->propagate_relations) {
757 const bNodeSocket &output_socket = node->output_socket(relation.to_geometry_output);
758 const bNodeSocket &input_socket = node->input_socket(relation.from_geometry_input);
759 if (!input_socket.is_available() || !output_socket.is_available()) {
760 continue;
761 }
762 const int dst_index = input_socket.index_in_tree();
763 const int src_index = output_socket.index_in_tree();
764 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
765 }
766 for (const aal::EvalRelation &relation : relations->eval_relations) {
767 const bNodeSocket &data_socket = node->input_socket(relation.geometry_input);
768 const bNodeSocket &reference_socket = node->input_socket(relation.field_input);
769 if (!data_socket.is_available() || !reference_socket.is_available()) {
770 continue;
771 }
772 r_required_data_by_socket[data_socket.index_in_tree()] |=
773 potential_reference_by_socket[reference_socket.index_in_tree()];
774 }
775 }
776
777 switch (node->type_legacy) {
778 /* Propagate from the geometry outputs to the geometry input. */
780 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
781 if (!zone) {
782 break;
783 }
784 const bNode *input_node = node;
785 const bNode *output_node = zone->output_node();
786 const int dst_index = input_node->input_socket(0).index_in_tree();
787 for (const bNodeSocket *output_socket : output_node->output_sockets()) {
788 if (output_socket->type == SOCK_GEOMETRY) {
789 const int src_index = output_socket->index_in_tree();
790 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
791 }
792 }
793 break;
794 }
796 const bNode *output_node = node;
797 const auto *storage = static_cast<NodeGeometryForeachGeometryElementOutput *>(
798 output_node->storage);
799
800 for (const int item_i : IndexRange(storage->generation_items.items_num)) {
801 const int src_index =
802 node->output_socket(1 + storage->main_items.items_num + item_i).index_in_tree();
803 const int dst_index =
804 node->input_socket(storage->main_items.items_num + item_i).index_in_tree();
805 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
806 }
807 break;
808 }
810 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
811 if (!zone) {
812 break;
813 }
814 /* Propagate within output node. */
815 const int items_num = node->output_sockets().size() - 1;
816 for (const int i : IndexRange(items_num)) {
817 const int src_index = node->output_socket(i).index_in_tree();
818 const int dst_index = node->input_socket(i).index_in_tree();
819 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
820 }
821 break;
822 }
824 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
825 if (!zone) {
826 break;
827 }
828 const bNode *input_node = node;
829 const bNode *output_node = zone->output_node();
830 const int items_num = output_node->output_sockets().size() - 1;
831 for (const int i : IndexRange(items_num)) {
832 const bNodeSocket &body_input_socket = input_node->output_socket(i + 1);
833 const bNodeSocket &body_output_socket = output_node->input_socket(i);
834 const int in_index = body_input_socket.index_in_tree();
835 const int out_index = body_output_socket.index_in_tree();
836 needs_extra_pass |= or_into_each_other(r_required_data_by_socket[in_index],
837 r_required_data_by_socket[out_index]);
838 }
839 break;
840 }
842 /* Data referenced by the closure is required on all the other inputs. */
843 const bNodeSocket &closure_socket = node->input_socket(0);
844 BitVector<> required_data_on_inputs =
845 potential_reference_by_socket[closure_socket.index_in_tree()];
846 /* Data required on outputs is also required on inputs. */
847 for (const bNodeSocket *socket : node->output_sockets()) {
848 required_data_on_inputs |= r_required_data_by_socket[socket->index_in_tree()];
849 }
850 /* References available on inputs are also required on the data inputs because they may be
851 * used by the closure. */
852 for (const bNodeSocket *socket : node->input_sockets()) {
853 if (can_contain_reference(eNodeSocketDatatype(socket->type))) {
854 required_data_on_inputs |= potential_reference_by_socket[socket->index_in_tree()];
855 }
856 }
857 for (const bNodeSocket *socket : node->input_sockets()) {
858 const int dst_index = socket->index_in_tree();
859 r_required_data_by_socket[dst_index] |= required_data_on_inputs;
860 }
861 break;
862 }
863 case NODE_CLOSURE_OUTPUT: {
864 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
865 if (!zone) {
866 break;
867 }
868 /* Data that's required on the closure is also required on all inputs of the closure. */
869 const bNodeSocket &output_socket = node->output_socket(0);
870 const BoundedBitSpan required_data =
871 r_required_data_by_socket[output_socket.index_in_tree()];
872 for (const bNodeSocket *input_socket : node->input_sockets()) {
873 r_required_data_by_socket[input_socket->index_in_tree()] |= required_data;
874 }
875 break;
876 }
877 }
878 }
879 return needs_extra_pass;
880}
881
883 private:
884 Vector<BitGroupVector<>> bit_groups_;
885
886 public:
888 : bit_groups_(bit_groups)
889 {
890 }
891
892 std::string socket_name(const bNodeSocket &socket) const override
893 {
894 Vector<std::string> extra_data;
895 for (const BitGroupVector<> &bit_group : bit_groups_) {
896 const BoundedBitSpan bits = bit_group[socket.index_in_tree()];
898 bits::foreach_1_index(bits, [&](const int i) { indices.append(i); });
899 extra_data.append(fmt::format("({})", fmt::join(indices, ",")));
900 }
901 return fmt::format("{} {}", socket.name, fmt::join(extra_data, " "));
902 }
903};
904
905static aal::RelationsInNode get_tree_relations(
906 const bNodeTree &tree,
907 const Span<ReferenceSetInfo> reference_sets,
908 const BitGroupVector<> &potential_data_by_socket,
909 const BitGroupVector<> &potential_reference_by_socket,
910 const BitGroupVector<> &required_data_by_socket)
911{
912 aal::RelationsInNode tree_relations;
913 const bNode *group_output_node = tree.group_output_node();
914
915 for (const int input_i : tree.interface_inputs().index_range()) {
916 const bNodeTreeInterfaceSocket &interface_input = *tree.interface_inputs()[input_i];
917 const eNodeSocketDatatype socket_type = interface_input.socket_typeinfo()->type;
918 if (can_contain_referenced_data(socket_type)) {
919 BitVector<> required_data(required_data_by_socket.group_size(), false);
920 for (const bNode *input_node : tree.group_input_nodes()) {
921 required_data |=
922 required_data_by_socket[input_node->output_socket(input_i).index_in_tree()];
923 }
924 bits::foreach_1_index(required_data, [&](const int reference_set_i) {
925 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
926 switch (reference_set.type) {
928 tree_relations.propagate_relations.append_non_duplicates(
929 {input_i, reference_set.index});
930 break;
931 }
933 tree_relations.eval_relations.append_non_duplicates({reference_set.index, input_i});
934 break;
935 }
936 default:
937 break;
938 }
939 });
940 }
941 }
942 if (group_output_node) {
943 for (const int output_i : tree.interface_outputs().index_range()) {
944 const bNodeSocket &socket = group_output_node->input_socket(output_i);
945 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(socket.type);
946 if (can_contain_reference(socket_type)) {
947 const BoundedBitSpan potential_references =
948 potential_reference_by_socket[socket.index_in_tree()];
949 bits::foreach_1_index(potential_references, [&](const int reference_set_i) {
950 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
951 switch (reference_set.type) {
953 tree_relations.reference_relations.append_non_duplicates(
954 {reference_set.index, output_i});
955 break;
956 }
957 default: {
958 break;
959 }
960 }
961 });
962 }
963 if (can_contain_referenced_data(socket_type)) {
964 const BoundedBitSpan potential_data = potential_data_by_socket[socket.index_in_tree()];
965 bits::foreach_1_index(potential_data, [&](const int reference_set_i) {
966 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
967 switch (reference_set.type) {
969 for (const bNodeSocket *other_socket :
970 group_output_node->input_sockets().drop_back(1))
971 {
972 if (!can_contain_reference(eNodeSocketDatatype(other_socket->type))) {
973 continue;
974 }
975 const BoundedBitSpan potential_references =
976 potential_reference_by_socket[other_socket->index_in_tree()];
977 if (potential_references[reference_set_i].test()) {
978 tree_relations.available_relations.append_non_duplicates(
979 {other_socket->index(), output_i});
980 }
981 }
982 break;
983 }
984 default: {
985 break;
986 }
987 }
988 });
989 }
990 }
991 }
992
993 return tree_relations;
994}
995
996static std::unique_ptr<ReferenceLifetimesInfo> make_reference_lifetimes_info(const bNodeTree &tree)
997{
998 tree.ensure_topology_cache();
999 tree.ensure_interface_cache();
1000 if (tree.has_available_link_cycle()) {
1001 return {};
1002 }
1003 const bNodeTreeZones *zones = tree.zones();
1004 if (zones == nullptr) {
1005 return {};
1006 }
1007
1008 std::unique_ptr<ReferenceLifetimesInfo> reference_lifetimes_info =
1009 std::make_unique<ReferenceLifetimesInfo>();
1010
1011 ResourceScope scope;
1013
1014 Vector<int> group_output_set_sources;
1015 MultiValueMap<const bNodeTreeZone *, int> output_set_sources_by_closure_zone;
1016 reference_lifetimes_info->reference_sets = find_reference_sets(
1017 tree, relations_by_node, group_output_set_sources, output_set_sources_by_closure_zone);
1018 const Span<ReferenceSetInfo> reference_sets = reference_lifetimes_info->reference_sets;
1019
1020 const int sockets_num = tree.all_sockets().size();
1021 const int reference_sets_num = reference_sets.size();
1022
1023 BitGroupVector<> potential_data_by_socket(sockets_num, reference_sets_num, false);
1024 BitGroupVector<> potential_reference_by_socket(sockets_num, reference_sets_num, false);
1026 tree, reference_sets, potential_data_by_socket, potential_reference_by_socket);
1027
1028 /* Propagate data and reference from left to right. This may need to be done multiple times
1029 * because there may be some back-links. */
1030 while (pass_left_to_right(
1031 tree, relations_by_node, potential_data_by_socket, potential_reference_by_socket))
1032 {
1033 }
1034
1035 BitGroupVector<> required_data_by_socket(sockets_num, reference_sets_num, false);
1037 reference_sets,
1038 group_output_set_sources,
1039 output_set_sources_by_closure_zone,
1040 potential_data_by_socket,
1041 potential_reference_by_socket,
1042 required_data_by_socket);
1043
1044 while (pass_right_to_left(
1045 tree, relations_by_node, potential_reference_by_socket, required_data_by_socket))
1046 {
1047 }
1048
1049 /* Make sure that all required data is also potentially available. */
1050 required_data_by_socket.all_bits() &= potential_data_by_socket.all_bits();
1051
1052/* Only useful when debugging the reference lifetimes analysis. */
1053#if 0
1054 std::cout << "\n\n"
1056 bNodeTreeBitGroupVectorOptions({potential_data_by_socket,
1057 potential_reference_by_socket,
1058 required_data_by_socket}))
1059
1060 << "\n\n";
1061#endif
1062
1063 reference_lifetimes_info->tree_relations = get_tree_relations(tree,
1064 reference_sets,
1065 potential_data_by_socket,
1066 potential_reference_by_socket,
1067 required_data_by_socket);
1068 reference_lifetimes_info->required_data_by_socket = std::move(required_data_by_socket);
1069 return reference_lifetimes_info;
1070}
1071
1073{
1074 std::unique_ptr<ReferenceLifetimesInfo> reference_lifetimes_info = make_reference_lifetimes_info(
1075 tree);
1076 std::unique_ptr<ReferenceLifetimesInfo> &stored_reference_lifetimes_info =
1077 tree.runtime->reference_lifetimes_info;
1078 if (!reference_lifetimes_info) {
1079 if (!tree.runtime->reference_lifetimes_info) {
1080 return false;
1081 }
1082 stored_reference_lifetimes_info.reset();
1083 return true;
1084 }
1085
1086 const bool interface_changed = stored_reference_lifetimes_info &&
1087 stored_reference_lifetimes_info->tree_relations !=
1088 reference_lifetimes_info->tree_relations;
1089 stored_reference_lifetimes_info = std::move(reference_lifetimes_info);
1090 return interface_changed;
1091}
1092
1093} // namespace blender::bke::node_tree_reference_lifetimes
#define NODE_REROUTE
Definition BKE_node.hh:813
#define NODE_CUSTOM_GROUP
Definition BKE_node.hh:816
#define NODE_GROUP
Definition BKE_node.hh:811
#define NODE_EVALUATE_CLOSURE
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_INPUT
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
#define GEO_NODE_SIMULATION_OUTPUT
#define NODE_CLOSURE_OUTPUT
#define GEO_NODE_BAKE
#define GEO_NODE_REPEAT_OUTPUT
#define GEO_NODE_REPEAT_INPUT
#define GEO_NODE_SIMULATION_INPUT
#define NODE_CLOSURE_INPUT
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
eNodeSocketDatatype
@ SOCK_CLOSURE
@ SOCK_CUSTOM
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
Span< Value > lookup(const Key &key) const
void add(const Key &key, const Value &value)
T & construct(Args &&...args)
constexpr Span drop_back(int64_t n) const
Definition BLI_span.hh:182
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
int64_t append_and_get_index(const T &value)
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
MutableSpan< T > as_mutable_span()
std::optional< int > output_node_id
const bNode * output_node() const
Vector< const bNodeLink * > border_links
std::optional< int > input_node_id
const bNode * input_node() const
Vector< bNodeTreeZone * > zones
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
KDTree_3d * tree
static ushort indices[]
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
uint64_t BitInt
void inplace_or_masked(FirstBitSpanT &&first_arg, const MaskBitSpanT &mask, const BitSpanT &...args)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
bool spans_equal_masked(const BitSpanT1 &a, const BitSpanT2 &b, const BitSpanT3 &mask)
static bool or_into_each_other(MutableBoundedBitSpan a, MutableBoundedBitSpan b)
static Array< const aal::RelationsInNode * > prepare_relations_by_node(const bNodeTree &tree, ResourceScope &scope)
static void set_initial_data_and_reference_bits(const bNodeTree &tree, const Span< ReferenceSetInfo > reference_sets, BitGroupVector<> &r_potential_data_by_socket, BitGroupVector<> &r_potential_reference_by_socket)
static Vector< ReferenceSetInfo > find_reference_sets(const bNodeTree &tree, const Span< const aal::RelationsInNode * > &relations_by_node, Vector< int > &r_group_output_reference_sets, MultiValueMap< const bNodeTreeZone *, int > &r_output_set_sources_by_closure_zone)
static void prepare_required_data_for_group_outputs(const bNodeTree &tree, const Span< ReferenceSetInfo > reference_sets, const Span< int > group_output_set_sources, const BitGroupVector<> &potential_data_by_socket, const BitGroupVector<> &potential_reference_by_socket, BitGroupVector<> &r_required_data_by_socket)
std::ostream & operator<<(std::ostream &stream, const ReferenceSetInfo &info)
static BitVector get_references_coming_from_outside_zone(const bNodeTreeZone &zone, const Span< const BitGroupVector<> * > sources)
static void prepare_required_data_for_closure_outputs(const bNodeTree &tree, const Span< ReferenceSetInfo > reference_sets, MultiValueMap< const bNodeTreeZone *, int > &output_set_sources_by_closure_zone, const BitGroupVector<> &potential_data_by_socket, const BitGroupVector<> &potential_reference_by_socket, BitGroupVector<> &r_required_data_by_socket)
bool can_contain_reference(eNodeSocketDatatype socket_type)
static aal::RelationsInNode get_tree_relations(const bNodeTree &tree, const Span< ReferenceSetInfo > reference_sets, const BitGroupVector<> &potential_data_by_socket, const BitGroupVector<> &potential_reference_by_socket, const BitGroupVector<> &required_data_by_socket)
bool can_contain_referenced_data(eNodeSocketDatatype socket_type)
static std::unique_ptr< ReferenceLifetimesInfo > make_reference_lifetimes_info(const bNodeTree &tree)
static const bNodeTreeZone * get_zone_of_node_if_full(const bNodeTreeZones *zones, const bNode &node)
static bool or_into_each_other_masked(MutableBoundedBitSpan a, MutableBoundedBitSpan b, const BoundedBitSpan mask)
static bool socket_may_have_reference(const bNodeSocket &socket)
static void prepare_required_data_for_outputs(const bNodeTree &tree, const Span< ReferenceSetInfo > reference_sets, const Span< int > group_output_set_sources, MultiValueMap< const bNodeTreeZone *, int > &output_set_sources_by_closure_zone, const BitGroupVector<> &potential_data_by_socket, const BitGroupVector<> &potential_reference_by_socket, BitGroupVector<> &r_required_data_by_socket)
static bool pass_left_to_right(const bNodeTree &tree, const Span< const aal::RelationsInNode * > &relations_by_node, BitGroupVector<> &r_potential_data_by_socket, BitGroupVector<> &r_potential_reference_by_socket)
static bool pass_right_to_left(const bNodeTree &tree, const Span< const aal::RelationsInNode * > &relations_by_node, const BitGroupVector<> &potential_reference_by_socket, BitGroupVector<> &r_required_data_by_socket)
std::string node_tree_to_dot(const bNodeTree &tree, const bNodeTreeToDotOptions &options=bNodeTreeToDotOptions())
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
int16_t type_legacy
void * storage
int32_t identifier
Defines a socket type.
Definition BKE_node.hh:158
eNodeSocketDatatype type
Definition BKE_node.hh:193
i
Definition text_draw.cc:230