Blender V4.5
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 bNodeTree &tree, const bNodeSocket &socket)
57{
58 return tree.runtime->field_states[socket.index_in_tree()] == FieldSocketState::IsField;
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(tree, 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(tree, 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(tree, *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(tree, *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(tree, 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
297 const bNodeTreeZones *zones = tree.zones();
298 if (!zones) {
299 return reference_sets;
300 }
301 for (const bNodeTreeZone *zone : zones->zones) {
302 const bNode &input_node = *zone->input_node();
303 const bNode &output_node = *zone->output_node();
304 if (output_node.type_legacy != GEO_NODE_CLOSURE_OUTPUT) {
305 continue;
306 }
307 const auto &storage = *static_cast<const NodeGeometryClosureOutput *>(output_node.storage);
308 const int old_reference_sets_count = reference_sets.size();
309 /* Handle references coming from field inputs in the closure. */
310 for (const int input_i : IndexRange(storage.input_items.items_num)) {
311 const bNodeSocket &socket = input_node.output_socket(input_i);
313 reference_sets.append({ReferenceSetType::ClosureInputReferenceSet, &socket});
314 }
315 }
316 /* Handle references required by output geometries in the closure. */
317 for (const int output_i : IndexRange(storage.output_items.items_num)) {
318 const bNodeSocket &socket = output_node.input_socket(output_i);
320 r_output_set_sources_by_closure_zone.add(
321 zone,
322 reference_sets.append_and_get_index({ReferenceSetType::ClosureOutputData, &socket}));
323 }
324 }
325 /* All references referenced passed into this zone may exist on the geometry inputs. */
326 MutableSpan<ReferenceSetInfo> new_reference_sets = reference_sets.as_mutable_span().drop_front(
327 old_reference_sets_count);
328 for (const int input_i : IndexRange(storage.input_items.items_num)) {
329 const bNodeSocket &socket = input_node.output_socket(input_i);
331 for (ReferenceSetInfo &source : new_reference_sets) {
332 source.potential_data_origins.append(&socket);
333 }
334 }
335 }
336 }
337 return reference_sets;
338}
339
341 const Span<ReferenceSetInfo> reference_sets,
342 BitGroupVector<> &r_potential_data_by_socket,
343 BitGroupVector<> &r_potential_reference_by_socket)
344{
345 for (const int reference_set_i : reference_sets.index_range()) {
346 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
347 for (const bNodeSocket *socket : reference_set.potential_data_origins) {
348 r_potential_data_by_socket[socket->index_in_tree()][reference_set_i].set();
349 }
350 switch (reference_set.type) {
353 r_potential_reference_by_socket[reference_set.socket->index_in_tree()][reference_set_i]
354 .set();
355 break;
356 }
358 for (const bNode *node : tree.group_input_nodes()) {
359 const bNodeSocket &socket = node->output_socket(reference_set.index);
360 r_potential_reference_by_socket[socket.index_in_tree()][reference_set_i].set();
361 }
362 break;
363 }
366 /* Nothing to do. */
367 break;
368 }
369 }
370 }
371}
372
374 const bNodeTreeZone &zone, const Span<const BitGroupVector<> *> sources)
375{
376 BitVector<> found(sources.first()->group_size(), false);
377 /* Gather references that are passed into the zone from the outside, either through the input
378 * node or border links. */
379 for (const bNodeSocket *socket : zone.input_node()->input_sockets()) {
380 const int src = socket->index_in_tree();
381 for (const BitGroupVector<> *source : sources) {
382 found |= (*source)[src];
383 }
384 }
385 for (const bNodeLink *link : zone.border_links) {
386 const int src = link->fromsock->index_in_tree();
387 for (const BitGroupVector<> *source : sources) {
388 found |= (*source)[src];
389 }
390 }
391 return found;
392}
393
398 const Span<const aal::RelationsInNode *> &relations_by_node,
399 BitGroupVector<> &r_potential_data_by_socket,
400 BitGroupVector<> &r_potential_reference_by_socket)
401{
402 bool needs_extra_pass = false;
403 const bNodeTreeZones *zones = tree.zones();
404 for (const bNode *node : tree.toposort_left_to_right()) {
405 for (const bNodeSocket *socket : node->input_sockets()) {
406 if (!socket->is_available()) {
407 continue;
408 }
409 const int dst_index = socket->index_in_tree();
410 for (const bNodeLink *link : socket->directly_linked_links()) {
411 if (!link->is_used()) {
412 continue;
413 }
414 const int src_index = link->fromsock->index_in_tree();
415 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
416 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
417 }
418 }
419 if (node->is_muted()) {
420 for (const bNodeLink &link : node->internal_links()) {
421 const bNodeSocket &input_socket = *link.fromsock;
422 const bNodeSocket &output_socket = *link.tosock;
423 if (!input_socket.is_available() || !output_socket.is_available()) {
424 continue;
425 }
426 const int src_index = input_socket.index_in_tree();
427 const int dst_index = output_socket.index_in_tree();
428 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
429 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
430 }
431 continue;
432 }
433 if (const aal::RelationsInNode *relations = relations_by_node[node->index()]) {
434 /* Propagate references. */
435 for (const aal::ReferenceRelation &relation : relations->reference_relations) {
436 const bNodeSocket &from_socket = node->input_socket(relation.from_field_input);
437 const bNodeSocket &to_socket = node->output_socket(relation.to_field_output);
438 if (!from_socket.is_available() || !to_socket.is_available()) {
439 continue;
440 }
441 const int src_index = from_socket.index_in_tree();
442 const int dst_index = to_socket.index_in_tree();
443 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
444 }
445 /* Propagate data. */
446 for (const aal::PropagateRelation &relation : relations->propagate_relations) {
447 const bNodeSocket &from_socket = node->input_socket(relation.from_geometry_input);
448 const bNodeSocket &to_socket = node->output_socket(relation.to_geometry_output);
449 if (!from_socket.is_available() || !to_socket.is_available()) {
450 continue;
451 }
452 const int src_index = from_socket.index_in_tree();
453 const int dst_index = to_socket.index_in_tree();
454 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
455 }
456 }
457 switch (node->type_legacy) {
458 /* This zone needs additional special handling because attributes from the input geometry
459 * are propagated to the output node. */
461 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
462 if (!zone) {
463 break;
464 }
465 const bNode *input_node = zone->input_node();
466 const bNode *output_node = node;
467 const auto *storage = static_cast<const NodeGeometryForeachGeometryElementOutput *>(
468 node->storage);
469 const int src_index = input_node->input_socket(0).index_in_tree();
470 for (const bNodeSocket *output_socket : output_node->output_sockets()) {
471 if (output_socket->type == SOCK_GEOMETRY) {
472 const int dst_index = output_socket->index_in_tree();
473 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
474 }
475 }
476
477 /* Propagate references from the inside to the outside. Like in the repeat zone, new
478 * references created in the zone stay local inside the zone and are not propagated to the
479 * outside. Instead, the foreach-element output node creates new references. */
480 const BitVector<> outside_references = get_references_coming_from_outside_zone(
481 *zone, {&r_potential_data_by_socket, &r_potential_reference_by_socket});
482 for (const int item_i : IndexRange(storage->generation_items.items_num)) {
483 const int src_index =
484 node->input_socket(storage->main_items.items_num + item_i).index_in_tree();
485 const int dst_index =
486 node->output_socket(1 + storage->main_items.items_num + item_i).index_in_tree();
487 bits::inplace_or_masked(r_potential_data_by_socket[dst_index],
488 outside_references,
489 r_potential_data_by_socket[src_index]);
490 bits::inplace_or_masked(r_potential_reference_by_socket[dst_index],
491 outside_references,
492 r_potential_reference_by_socket[src_index]);
493 }
494 break;
495 }
497 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
498 if (!zone) {
499 break;
500 }
501 const bNode &input_node = *zone->input_node();
502 /* Data referenced by border links may also be passed into the closure as input. */
503 const BitVector<> outside_references = get_references_coming_from_outside_zone(
504 *zone, {&r_potential_data_by_socket, &r_potential_reference_by_socket});
505 for (const int i : node->output_sockets().index_range()) {
506 const int dst_index = input_node.output_socket(i).index_in_tree();
507 r_potential_data_by_socket[dst_index] |= outside_references;
508 r_potential_reference_by_socket[dst_index] |= outside_references;
509 }
510 break;
511 }
513 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
514 if (!zone) {
515 break;
516 }
517 const bNode &output_node = *zone->output_node();
518 /* References passed through border links are referenced by the closure. */
519 const BitVector<> passed_in_references = get_references_coming_from_outside_zone(
520 *zone, {&r_potential_reference_by_socket});
521 const int dst_index = output_node.output_socket(0).index_in_tree();
522 for (const int i : node->input_sockets().index_range()) {
523 const int src_index = output_node.input_socket(i).index_in_tree();
524 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
525 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
526 r_potential_reference_by_socket[dst_index] |= passed_in_references;
527 }
528 break;
529 }
531 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
532 if (!zone) {
533 break;
534 }
535 const bNode &input_node = *zone->input_node();
536 const bNode &output_node = *zone->output_node();
537 const int items_num = output_node.output_sockets().size() - 1;
538
539 /* Handle data propagation in the case when the iteration count is zero. */
540 for (const int i : IndexRange(items_num)) {
541 const int src_index = input_node.input_socket(i + 1).index_in_tree();
542 const int dst_index = output_node.output_socket(i).index_in_tree();
543 r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index];
544 r_potential_reference_by_socket[dst_index] |= r_potential_reference_by_socket[src_index];
545 }
546
547 const BitVector<> outside_references = get_references_coming_from_outside_zone(
548 *zone, {&r_potential_data_by_socket, &r_potential_reference_by_socket});
549
550 /* Propagate within output node. */
551 for (const int i : IndexRange(items_num)) {
552 const int src_index = output_node.input_socket(i).index_in_tree();
553 const int dst_index = output_node.output_socket(i).index_in_tree();
554 bits::inplace_or_masked(r_potential_data_by_socket[dst_index],
555 outside_references,
556 r_potential_data_by_socket[src_index]);
557 bits::inplace_or_masked(r_potential_reference_by_socket[dst_index],
558 outside_references,
559 r_potential_reference_by_socket[src_index]);
560 }
561
562 /* Ensure that references and data on the input and output node are equal. Since this may
563 * propagate information backwards, an additional pass can be necessary. */
564 for (const int i : IndexRange(items_num)) {
565 const bNodeSocket &body_input_socket = input_node.output_socket(i + 1);
566 const bNodeSocket &body_output_socket = output_node.input_socket(i);
567 const int in_index = body_output_socket.index_in_tree();
568 const int out_index = body_input_socket.index_in_tree();
569 needs_extra_pass |= or_into_each_other_masked(r_potential_data_by_socket[in_index],
570 r_potential_data_by_socket[out_index],
571 outside_references);
572 needs_extra_pass |= or_into_each_other_masked(r_potential_reference_by_socket[in_index],
573 r_potential_reference_by_socket[out_index],
574 outside_references);
575 }
576 break;
577 }
578 }
579 }
580 return needs_extra_pass;
581}
582
584 const bNodeTree &tree,
585 const Span<ReferenceSetInfo> reference_sets,
586 const Span<int> group_output_set_sources,
587 const BitGroupVector<> &potential_data_by_socket,
588 const BitGroupVector<> &potential_reference_by_socket,
589 BitGroupVector<> &r_required_data_by_socket)
590{
591 if (const bNode *group_output_node = tree.group_output_node()) {
592 const Span<const bNodeSocket *> sockets = group_output_node->input_sockets().drop_back(1);
593 for (const int reference_set_i : group_output_set_sources) {
594 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
596 const int index = sockets[reference_set.index]->index_in_tree();
597 r_required_data_by_socket[index][reference_set_i].set();
598 }
599 BitVector<> potential_output_references(reference_sets.size(), false);
600 for (const bNodeSocket *socket : sockets) {
601 potential_output_references |= potential_reference_by_socket[socket->index_in_tree()];
602 }
603 for (const bNodeSocket *socket : sockets) {
605 continue;
606 }
607 const int index = socket->index_in_tree();
608 r_required_data_by_socket[index] |= potential_output_references;
609 /* Make sure that only available data is also required. This is enforced in the end anyway,
610 * but may reduce some unnecessary work. */
611 r_required_data_by_socket[index] &= potential_data_by_socket[index];
612 }
613 }
614}
615
617 const bNodeTree &tree,
618 const Span<ReferenceSetInfo> reference_sets,
619 MultiValueMap<const bNodeTreeZone *, int> &output_set_sources_by_closure_zone,
620 const BitGroupVector<> &potential_data_by_socket,
621 const BitGroupVector<> &potential_reference_by_socket,
622 BitGroupVector<> &r_required_data_by_socket)
623{
624 const bNodeTreeZones *zones = tree.zones();
625 if (!zones) {
626 return;
627 }
628 for (const bNodeTreeZone *zone : zones->zones) {
629 if (!zone->input_node_id || !zone->output_node_id) {
630 continue;
631 }
632 const bNode &output_node = *zone->output_node();
633 if (output_node.type_legacy != GEO_NODE_CLOSURE_OUTPUT) {
634 continue;
635 }
636 const Span<int> closure_output_set_sources = output_set_sources_by_closure_zone.lookup(zone);
637 for (const int reference_set_i : closure_output_set_sources) {
638 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
640 r_required_data_by_socket[reference_set.socket->index_in_tree()][reference_set_i].set();
641 }
642 BitVector<> potential_output_references(reference_sets.size(), false);
643 const Span<const bNodeSocket *> sockets = output_node.input_sockets().drop_back(1);
644 for (const bNodeSocket *socket : sockets) {
645 potential_output_references |= potential_reference_by_socket[socket->index_in_tree()];
646 }
647 for (const bNodeSocket *socket : sockets) {
649 continue;
650 }
651 const int index = socket->index_in_tree();
652 r_required_data_by_socket[index] |= potential_output_references;
653 /* Make sure that only available data is also required. This is enforced in the end anyway,
654 * but may reduce some unnecessary work. */
655 r_required_data_by_socket[index] &= potential_data_by_socket[index];
656 }
657 }
658}
659
661 const bNodeTree &tree,
662 const Span<ReferenceSetInfo> reference_sets,
663 const Span<int> group_output_set_sources,
664 MultiValueMap<const bNodeTreeZone *, int> &output_set_sources_by_closure_zone,
665 const BitGroupVector<> &potential_data_by_socket,
666 const BitGroupVector<> &potential_reference_by_socket,
667 BitGroupVector<> &r_required_data_by_socket)
668{
670 reference_sets,
671 group_output_set_sources,
672 potential_data_by_socket,
673 potential_reference_by_socket,
674 r_required_data_by_socket);
676 reference_sets,
677 output_set_sources_by_closure_zone,
678 potential_data_by_socket,
679 potential_reference_by_socket,
680 r_required_data_by_socket);
681}
682
684 const Span<const aal::RelationsInNode *> &relations_by_node,
685 const BitGroupVector<> &potential_reference_by_socket,
686 BitGroupVector<> &r_required_data_by_socket)
687{
688 bool needs_extra_pass = false;
689 const bNodeTreeZones *zones = tree.zones();
690 for (const bNode *node : tree.toposort_right_to_left()) {
691 for (const bNodeSocket *socket : node->output_sockets()) {
692 if (!socket->is_available()) {
693 continue;
694 }
695 const int dst_index = socket->index_in_tree();
696 for (const bNodeLink *link : socket->directly_linked_links()) {
697 if (!link->is_used()) {
698 continue;
699 }
700 const int src_index = link->tosock->index_in_tree();
701 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
702 }
703 }
704 if (node->is_muted()) {
705 for (const bNodeLink &link : node->internal_links()) {
706 const bNodeSocket &input_socket = *link.fromsock;
707 const bNodeSocket &output_socket = *link.tosock;
708 if (!input_socket.is_available() || !output_socket.is_available()) {
709 continue;
710 }
711 const int dst_index = input_socket.index_in_tree();
712 const int src_index = output_socket.index_in_tree();
713 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
714 }
715 continue;
716 }
717 if (const aal::RelationsInNode *relations = relations_by_node[node->index()]) {
718 for (const aal::PropagateRelation &relation : relations->propagate_relations) {
719 const bNodeSocket &output_socket = node->output_socket(relation.to_geometry_output);
720 const bNodeSocket &input_socket = node->input_socket(relation.from_geometry_input);
721 if (!input_socket.is_available() || !output_socket.is_available()) {
722 continue;
723 }
724 const int dst_index = input_socket.index_in_tree();
725 const int src_index = output_socket.index_in_tree();
726 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
727 }
728 for (const aal::EvalRelation &relation : relations->eval_relations) {
729 const bNodeSocket &data_socket = node->input_socket(relation.geometry_input);
730 const bNodeSocket &reference_socket = node->input_socket(relation.field_input);
731 if (!data_socket.is_available() || !reference_socket.is_available()) {
732 continue;
733 }
734 r_required_data_by_socket[data_socket.index_in_tree()] |=
735 potential_reference_by_socket[reference_socket.index_in_tree()];
736 }
737 }
738
739 switch (node->type_legacy) {
740 /* Propagate from the geometry outputs to the geometry input. */
742 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
743 if (!zone) {
744 break;
745 }
746 const bNode *input_node = node;
747 const bNode *output_node = zone->output_node();
748 const int dst_index = input_node->input_socket(0).index_in_tree();
749 for (const bNodeSocket *output_socket : output_node->output_sockets()) {
750 if (output_socket->type == SOCK_GEOMETRY) {
751 const int src_index = output_socket->index_in_tree();
752 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
753 }
754 }
755 break;
756 }
758 const bNode *output_node = node;
759 const auto *storage = static_cast<NodeGeometryForeachGeometryElementOutput *>(
760 output_node->storage);
761
762 for (const int item_i : IndexRange(storage->generation_items.items_num)) {
763 const int src_index =
764 node->output_socket(1 + storage->main_items.items_num + item_i).index_in_tree();
765 const int dst_index =
766 node->input_socket(storage->main_items.items_num + item_i).index_in_tree();
767 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
768 }
769 break;
770 }
772 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
773 if (!zone) {
774 break;
775 }
776 /* Propagate within output node. */
777 const int items_num = node->output_sockets().size() - 1;
778 for (const int i : IndexRange(items_num)) {
779 const int src_index = node->output_socket(i).index_in_tree();
780 const int dst_index = node->input_socket(i).index_in_tree();
781 r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index];
782 }
783 break;
784 }
786 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
787 if (!zone) {
788 break;
789 }
790 const bNode *input_node = node;
791 const bNode *output_node = zone->output_node();
792 const int items_num = output_node->output_sockets().size() - 1;
793 for (const int i : IndexRange(items_num)) {
794 const bNodeSocket &body_input_socket = input_node->output_socket(i + 1);
795 const bNodeSocket &body_output_socket = output_node->input_socket(i);
796 const int in_index = body_input_socket.index_in_tree();
797 const int out_index = body_output_socket.index_in_tree();
798 needs_extra_pass |= or_into_each_other(r_required_data_by_socket[in_index],
799 r_required_data_by_socket[out_index]);
800 }
801 break;
802 }
804 /* Data referenced by the closure is required on all the other inputs. */
805 const bNodeSocket &closure_socket = node->input_socket(0);
806 const BoundedBitSpan required_references =
807 potential_reference_by_socket[closure_socket.index_in_tree()];
808 for (const bNodeSocket *input_socket : node->input_sockets().drop_front(1)) {
809 const int dst_index = input_socket->index_in_tree();
810 r_required_data_by_socket[dst_index] |= required_references;
811 }
812 break;
813 }
815 const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node);
816 if (!zone) {
817 break;
818 }
819 /* Data that's required on the closure is also required on all inputs of the closure. */
820 const bNodeSocket &output_socket = node->output_socket(0);
821 const BoundedBitSpan required_data =
822 r_required_data_by_socket[output_socket.index_in_tree()];
823 for (const bNodeSocket *input_socket : node->input_sockets()) {
824 r_required_data_by_socket[input_socket->index_in_tree()] |= required_data;
825 }
826 break;
827 }
828 }
829 }
830 return needs_extra_pass;
831}
832
834 private:
835 Vector<BitGroupVector<>> bit_groups_;
836
837 public:
839 : bit_groups_(bit_groups)
840 {
841 }
842
843 std::string socket_name(const bNodeSocket &socket) const override
844 {
845 Vector<std::string> extra_data;
846 for (const BitGroupVector<> &bit_group : bit_groups_) {
847 const BoundedBitSpan bits = bit_group[socket.index_in_tree()];
849 bits::foreach_1_index(bits, [&](const int i) { indices.append(i); });
850 extra_data.append(fmt::format("({})", fmt::join(indices, ",")));
851 }
852 return fmt::format("{} {}", socket.name, fmt::join(extra_data, " "));
853 }
854};
855
856static aal::RelationsInNode get_tree_relations(
857 const bNodeTree &tree,
858 const Span<ReferenceSetInfo> reference_sets,
859 const BitGroupVector<> &potential_data_by_socket,
860 const BitGroupVector<> &potential_reference_by_socket,
861 const BitGroupVector<> &required_data_by_socket)
862{
863 aal::RelationsInNode tree_relations;
864 const bNode *group_output_node = tree.group_output_node();
865
866 for (const int input_i : tree.interface_inputs().index_range()) {
867 const bNodeTreeInterfaceSocket &interface_input = *tree.interface_inputs()[input_i];
868 const eNodeSocketDatatype socket_type = interface_input.socket_typeinfo()->type;
869 if (can_contain_referenced_data(socket_type)) {
870 BitVector<> required_data(required_data_by_socket.group_size(), false);
871 for (const bNode *input_node : tree.group_input_nodes()) {
872 required_data |=
873 required_data_by_socket[input_node->output_socket(input_i).index_in_tree()];
874 }
875 bits::foreach_1_index(required_data, [&](const int reference_set_i) {
876 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
877 switch (reference_set.type) {
879 tree_relations.propagate_relations.append_non_duplicates(
880 {input_i, reference_set.index});
881 break;
882 }
884 tree_relations.eval_relations.append_non_duplicates({reference_set.index, input_i});
885 break;
886 }
887 default:
888 break;
889 }
890 });
891 }
892 }
893 if (group_output_node) {
894 for (const int output_i : tree.interface_outputs().index_range()) {
895 const bNodeSocket &socket = group_output_node->input_socket(output_i);
896 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(socket.type);
897 if (can_contain_reference(socket_type)) {
898 const BoundedBitSpan potential_references =
899 potential_reference_by_socket[socket.index_in_tree()];
900 bits::foreach_1_index(potential_references, [&](const int reference_set_i) {
901 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
902 switch (reference_set.type) {
904 tree_relations.reference_relations.append_non_duplicates(
905 {reference_set.index, output_i});
906 break;
907 }
908 default: {
909 break;
910 }
911 }
912 });
913 }
914 if (can_contain_referenced_data(socket_type)) {
915 const BoundedBitSpan potential_data = potential_data_by_socket[socket.index_in_tree()];
916 bits::foreach_1_index(potential_data, [&](const int reference_set_i) {
917 const ReferenceSetInfo &reference_set = reference_sets[reference_set_i];
918 switch (reference_set.type) {
920 for (const bNodeSocket *other_socket :
921 group_output_node->input_sockets().drop_back(1))
922 {
923 if (!can_contain_reference(eNodeSocketDatatype(other_socket->type))) {
924 continue;
925 }
926 const BoundedBitSpan potential_references =
927 potential_reference_by_socket[other_socket->index_in_tree()];
928 if (potential_references[reference_set_i].test()) {
929 tree_relations.available_relations.append_non_duplicates(
930 {other_socket->index(), output_i});
931 }
932 }
933 break;
934 }
935 default: {
936 break;
937 }
938 }
939 });
940 }
941 }
942 }
943
944 return tree_relations;
945}
946
947static std::unique_ptr<ReferenceLifetimesInfo> make_reference_lifetimes_info(const bNodeTree &tree)
948{
949 tree.ensure_topology_cache();
950 tree.ensure_interface_cache();
951 if (tree.has_available_link_cycle()) {
952 return {};
953 }
954 const bNodeTreeZones *zones = tree.zones();
955 if (zones == nullptr) {
956 return {};
957 }
958
959 std::unique_ptr<ReferenceLifetimesInfo> reference_lifetimes_info =
960 std::make_unique<ReferenceLifetimesInfo>();
961
962 ResourceScope scope;
964
965 Vector<int> group_output_set_sources;
966 MultiValueMap<const bNodeTreeZone *, int> output_set_sources_by_closure_zone;
967 reference_lifetimes_info->reference_sets = find_reference_sets(
968 tree, relations_by_node, group_output_set_sources, output_set_sources_by_closure_zone);
969 const Span<ReferenceSetInfo> reference_sets = reference_lifetimes_info->reference_sets;
970
971 const int sockets_num = tree.all_sockets().size();
972 const int reference_sets_num = reference_sets.size();
973
974 BitGroupVector<> potential_data_by_socket(sockets_num, reference_sets_num, false);
975 BitGroupVector<> potential_reference_by_socket(sockets_num, reference_sets_num, false);
977 tree, reference_sets, potential_data_by_socket, potential_reference_by_socket);
978
979 /* Propagate data and reference from left to right. This may need to be done multiple times
980 * because there may be some back-links. */
981 while (pass_left_to_right(
982 tree, relations_by_node, potential_data_by_socket, potential_reference_by_socket))
983 {
984 }
985
986 BitGroupVector<> required_data_by_socket(sockets_num, reference_sets_num, false);
988 reference_sets,
989 group_output_set_sources,
990 output_set_sources_by_closure_zone,
991 potential_data_by_socket,
992 potential_reference_by_socket,
993 required_data_by_socket);
994
995 while (pass_right_to_left(
996 tree, relations_by_node, potential_reference_by_socket, required_data_by_socket))
997 {
998 }
999
1000 /* Make sure that all required data is also potentially available. */
1001 required_data_by_socket.all_bits() &= potential_data_by_socket.all_bits();
1002
1003/* Only useful when debugging the reference lifetimes analysis. */
1004#if 0
1005 std::cout << "\n\n"
1008 {potential_reference_by_socket, required_data_by_socket}))
1009
1010 << "\n\n";
1011#endif
1012
1013 reference_lifetimes_info->tree_relations = get_tree_relations(tree,
1014 reference_sets,
1015 potential_data_by_socket,
1016 potential_reference_by_socket,
1017 required_data_by_socket);
1018 reference_lifetimes_info->required_data_by_socket = std::move(required_data_by_socket);
1019 return reference_lifetimes_info;
1020}
1021
1023{
1024 std::unique_ptr<ReferenceLifetimesInfo> reference_lifetimes_info = make_reference_lifetimes_info(
1025 tree);
1026 std::unique_ptr<ReferenceLifetimesInfo> &stored_reference_lifetimes_info =
1027 tree.runtime->reference_lifetimes_info;
1028 if (!reference_lifetimes_info) {
1029 if (!tree.runtime->reference_lifetimes_info) {
1030 return false;
1031 }
1032 stored_reference_lifetimes_info.reset();
1033 return true;
1034 }
1035
1036 const bool interface_changed = stored_reference_lifetimes_info &&
1037 stored_reference_lifetimes_info->tree_relations !=
1038 reference_lifetimes_info->tree_relations;
1039 stored_reference_lifetimes_info = std::move(reference_lifetimes_info);
1040 return interface_changed;
1041}
1042
1043} // namespace blender::bke::node_tree_reference_lifetimes
#define NODE_REROUTE
Definition BKE_node.hh:798
#define NODE_CUSTOM_GROUP
Definition BKE_node.hh:801
#define NODE_GROUP
Definition BKE_node.hh:796
#define GEO_NODE_CLOSURE_OUTPUT
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_INPUT
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
#define GEO_NODE_SIMULATION_OUTPUT
#define GEO_NODE_CLOSURE_INPUT
#define GEO_NODE_EVALUATE_CLOSURE
#define GEO_NODE_BAKE
#define GEO_NODE_REPEAT_OUTPUT
#define GEO_NODE_REPEAT_INPUT
#define GEO_NODE_SIMULATION_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
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 bool socket_may_have_reference(const bNodeTree &tree, const bNodeSocket &socket)
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 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:152
eNodeSocketDatatype type
Definition BKE_node.hh:187
i
Definition text_draw.cc:230