From a848b376d43b94fa7b6b5e82f94ffb35cc8c9caa Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 6 Jan 2025 18:06:20 +0100 Subject: [PATCH] Fix #132408: crash when outputting anonymous attribute from foreach zone The issue was that the propagation of referenced anonymous attributes treated geometry outputs of the foreach zone as "normal". That means that every anonymous attributes referenced by the input socket would also be referenced by the output socket. However, just like in the repeat zone, this so called "propagate relation" needs some special behavior, because anonymous attributes references created inside a zone have to remain inside that zone. Instead, the output node creates a new anonymous attribute reference that is used outside of the zone. Note, this is the same as #132560 but also implements the right-to-left pass, whereas before only the left-to-right pass was implemented. Pull Request: https://projects.blender.org/blender/blender/pulls/132607 --- .../intern/node_tree_reference_lifetimes.cc | 34 +++++++++++++++++++ .../node_geo_foreach_geometry_element.cc | 6 ---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/node_tree_reference_lifetimes.cc b/source/blender/blenkernel/intern/node_tree_reference_lifetimes.cc index 5edf6388734..2afebd6705f 100644 --- a/source/blender/blenkernel/intern/node_tree_reference_lifetimes.cc +++ b/source/blender/blenkernel/intern/node_tree_reference_lifetimes.cc @@ -414,6 +414,8 @@ static bool pass_left_to_right(const bNodeTree &tree, } const bNode *input_node = zone->input_node; const bNode *output_node = node; + const auto *storage = static_cast( + node->storage); const int src_index = input_node->input_socket(0).index_in_tree(); for (const bNodeSocket *output_socket : output_node->output_sockets()) { if (output_socket->type == SOCK_GEOMETRY) { @@ -421,6 +423,24 @@ static bool pass_left_to_right(const bNodeTree &tree, r_potential_data_by_socket[dst_index] |= r_potential_data_by_socket[src_index]; } } + + /* Propagate references from the inside to the outside. Like in the repeat zone, new + * references created in the zone stay local inside the zone and are not propagated to the + * outside. Instead, the foreach-element output node creates new references. */ + const BitVector<> outside_references = get_references_coming_from_outside_zone( + *zone, r_potential_data_by_socket, r_potential_reference_by_socket); + for (const int item_i : IndexRange(storage->generation_items.items_num)) { + const int src_index = + node->input_socket(storage->main_items.items_num + item_i).index_in_tree(); + const int dst_index = + node->output_socket(1 + storage->main_items.items_num + item_i).index_in_tree(); + bits::inplace_or_masked(r_potential_data_by_socket[dst_index], + outside_references, + r_potential_data_by_socket[src_index]); + bits::inplace_or_masked(r_potential_reference_by_socket[dst_index], + outside_references, + r_potential_reference_by_socket[src_index]); + } break; } case GEO_NODE_REPEAT_OUTPUT: { @@ -584,6 +604,20 @@ static bool pass_right_to_left(const bNodeTree &tree, } break; } + case GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT: { + const bNode *output_node = node; + const auto *storage = static_cast( + output_node->storage); + + for (const int item_i : IndexRange(storage->generation_items.items_num)) { + const int src_index = + node->output_socket(1 + storage->main_items.items_num + item_i).index_in_tree(); + const int dst_index = + node->input_socket(storage->main_items.items_num + item_i).index_in_tree(); + r_required_data_by_socket[dst_index] |= r_required_data_by_socket[src_index]; + } + break; + } case GEO_NODE_REPEAT_OUTPUT: { const bNodeTreeZone *zone = get_zone_of_node_if_full(zones, *node); if (!zone) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_foreach_geometry_element.cc b/source/blender/nodes/geometry/nodes/node_geo_foreach_geometry_element.cc index 56f05e157d6..edbecfc2afc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_foreach_geometry_element.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_foreach_geometry_element.cc @@ -236,8 +236,6 @@ static void node_declare(NodeDeclarationBuilder &b) "The original input geometry with potentially new attributes that are output by the " "zone"); - aal::RelationsInNode &relations = b.get_anonymous_attribute_relations(); - const bNode *node = b.node_or_null(); const bNodeTree *tree = b.tree_or_null(); if (node && tree) { @@ -284,10 +282,6 @@ static void node_declare(NodeDeclarationBuilder &b) if (socket_type == SOCK_GEOMETRY) { previous_input_geometry_index = input_decl.index(); previous_output_geometry_index = output_decl.index(); - aal::PropagateRelation relation; - relation.from_geometry_input = input_decl.index(); - relation.to_geometry_output = output_decl.index(); - relations.propagate_relations.append(relation); input_decl.description( "Geometry generated in the current iteration. Will be joined with geometries from all "