From ca32fb604ef720a7b553dafe2c114d1d9e0e4593 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 24 Apr 2023 11:42:05 +0200 Subject: [PATCH] Geometry Nodes: support outputting field without computing full node Many nodes output anonymous attributes (e.g. the top selection in the Cylinder node). The actual data is only contained in the geometry output though. The field output just contains a reference to this data (essentially just the generated name of an attribute). This data can be output even without computing the geometry itself. As of right now, this only simplifies the code a bit, but does not have a bigger impact, because to use the anonymous attribute, you always need the geometry anyway. However, with the upcoming simulation nodes, it's possible to create the anonymous attribute in one frame and to access it in another frame. In the other frame we only need the anonymous attribute reference and don't have to create the actual geometry again. Skipping creating the actual attribute on the geometry can have a significant performance benefit. --- source/blender/nodes/NOD_geometry_exec.hh | 36 +--- source/blender/nodes/NOD_node_declaration.hh | 4 +- .../nodes/node_geo_attribute_capture.cc | 30 ---- .../nodes/geometry/nodes/node_geo_boolean.cc | 5 - .../nodes/node_geo_curve_primitive_star.cc | 3 - .../nodes/node_geo_curve_to_points.cc | 15 -- .../node_geo_distribute_points_on_faces.cc | 13 -- .../nodes/node_geo_duplicate_elements.cc | 6 - .../geometry/nodes/node_geo_extrude_mesh.cc | 10 -- .../nodes/node_geo_interpolate_curves.cc | 10 -- .../nodes/node_geo_mesh_primitive_cone.cc | 23 --- .../nodes/node_geo_mesh_primitive_cube.cc | 6 - .../nodes/node_geo_mesh_primitive_cylinder.cc | 23 --- .../nodes/node_geo_mesh_primitive_grid.cc | 6 - .../node_geo_mesh_primitive_ico_sphere.cc | 6 - .../node_geo_mesh_primitive_uv_sphere.cc | 5 - .../nodes/node_geo_string_to_curves.cc | 6 - .../intern/geometry_nodes_lazy_function.cc | 165 +++++++++++++++++- .../nodes/intern/node_geometry_exec.cc | 35 ---- 19 files changed, 173 insertions(+), 234 deletions(-) diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 5af97ea8fcb..085fd3d65f4 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -42,23 +42,6 @@ using fn::ValueOrField; using geo_eval_log::NamedAttributeUsage; using geo_eval_log::NodeWarningType; -/** - * An anonymous attribute created by a node. - */ -class NodeAnonymousAttributeID : public AnonymousAttributeID { - std::string long_name_; - std::string socket_name_; - - public: - NodeAnonymousAttributeID(const Object &object, - const ComputeContext &compute_context, - const bNode &bnode, - const StringRef identifier, - const StringRef name); - - std::string user_name() const override; -}; - class GeoNodeExecParams { private: const bNode &node_; @@ -66,18 +49,22 @@ class GeoNodeExecParams { const lf::Context &lf_context_; const Span lf_input_for_output_bsocket_usage_; const Span lf_input_for_attribute_propagation_to_output_; + const FunctionRef get_output_attribute_id_; public: GeoNodeExecParams(const bNode &node, lf::Params ¶ms, const lf::Context &lf_context, const Span lf_input_for_output_bsocket_usage, - const Span lf_input_for_attribute_propagation_to_output) + const Span lf_input_for_attribute_propagation_to_output, + const FunctionRef get_output_attribute_id) : node_(node), params_(params), lf_context_(lf_context), lf_input_for_output_bsocket_usage_(lf_input_for_output_bsocket_usage), - lf_input_for_attribute_propagation_to_output_(lf_input_for_attribute_propagation_to_output) + lf_input_for_attribute_propagation_to_output_( + lf_input_for_attribute_propagation_to_output), + get_output_attribute_id_(get_output_attribute_id) { } @@ -240,8 +227,6 @@ class GeoNodeExecParams { */ void error_message_add(const NodeWarningType type, StringRef message) const; - std::string attribute_producer_name() const; - void set_default_remaining_outputs(); void used_named_attribute(StringRef attribute_name, NamedAttributeUsage usage); @@ -268,14 +253,7 @@ class GeoNodeExecParams { return {}; } const bNodeSocket &output_socket = node_.output_by_identifier(output_identifier); - const GeoNodesLFUserData &user_data = *this->user_data(); - const ComputeContext &compute_context = *user_data.compute_context; - return MEM_new(__func__, - *user_data.modifier_data->self_object, - compute_context, - node_, - output_identifier, - output_socket.name); + return get_output_attribute_id_(output_socket.index()); } /** diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index e9eff6bf625..6c5f6699eb4 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -322,7 +322,9 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder { /** * For inputs this means that the input field is evaluated on all geometry inputs. For outputs * it means that this contains an anonymous attribute reference that is available on all geometry - * outputs. + * outputs. This sockets value does not have to be output manually in the node. It's done + * automatically by #LazyFunctionForGeometryNode. This allows outputting this field even if the + * geometry output does not have to be computed. */ Self &field_on_all() { diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 6718a0b0d78..6d5596cda27 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -174,8 +174,6 @@ static void node_geo_exec(GeoNodeExecParams params) break; } - const CPPType &type = field.cpp_type(); - /* Run on the instances component separately to only affect the top level of instances. */ if (domain == ATTR_DOMAIN_INSTANCE) { if (geometry_set.has_instances()) { @@ -198,34 +196,6 @@ static void node_geo_exec(GeoNodeExecParams params) }); } - GField output_field{std::make_shared( - std::move(attribute_id), type, params.attribute_producer_name())}; - - switch (data_type) { - case CD_PROP_FLOAT: { - params.set_output(output_identifier, Field(output_field)); - break; - } - case CD_PROP_FLOAT3: { - params.set_output(output_identifier, Field(output_field)); - break; - } - case CD_PROP_COLOR: { - params.set_output(output_identifier, Field(output_field)); - break; - } - case CD_PROP_BOOL: { - params.set_output(output_identifier, Field(output_field)); - break; - } - case CD_PROP_INT32: { - params.set_output(output_identifier, Field(output_field)); - break; - } - default: - break; - } - params.set_output("Geometry", geometry_set); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index b1885970071..0457ab10f36 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -160,11 +160,6 @@ static void node_geo_exec(GeoNodeExecParams params) selection.span[i] = true; } selection.finish(); - - params.set_output( - "Intersecting Edges", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name())); } params.set_output("Mesh", GeometrySet::create_with_mesh(result)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index acf3654a166..402e396083c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -81,9 +81,6 @@ static void node_geo_exec(GeoNodeExecParams params) if (AnonymousAttributeIDPtr outer_points_id = params.get_output_anonymous_attribute_id_if_needed( "Outer Points")) { create_selection_output(output.get_component_for_write(), outer_points_id); - params.set_output("Outer Points", - AnonymousAttributeFieldInput::Create( - std::move(outer_points_id), params.attribute_producer_name())); } params.set_output("Curve", std::move(output)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 22286969c24..bae8dc49ef2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -200,21 +200,6 @@ static void node_geo_exec(GeoNodeExecParams params) } params.set_output("Points", std::move(geometry_set)); - if (tangent_anonymous_id) { - params.set_output("Tangent", - AnonymousAttributeFieldInput::Create( - std::move(tangent_anonymous_id), params.attribute_producer_name())); - } - if (normal_anonymous_id) { - params.set_output("Normal", - AnonymousAttributeFieldInput::Create( - std::move(normal_anonymous_id), params.attribute_producer_name())); - } - if (rotation_anonymous_id) { - params.set_output("Rotation", - AnonymousAttributeFieldInput::Create( - std::move(rotation_anonymous_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_curve_to_points_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index b4bc18c465c..5a389203345 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -590,19 +590,6 @@ static void node_geo_exec(GeoNodeExecParams params) }); params.set_output("Points", std::move(geometry_set)); - - if (attribute_outputs.normal_id) { - params.set_output( - "Normal", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.normal_id), - params.attribute_producer_name())); - } - if (attribute_outputs.rotation_id) { - params.set_output( - "Rotation", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.rotation_id), - params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_distribute_points_on_faces_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 68461dfe7b1..0040fb6305e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -1098,12 +1098,6 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - if (attribute_outputs.duplicate_index) { - params.set_output( - "Duplicate Index", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.duplicate_index), - params.attribute_producer_name())); - } params.set_output("Geometry", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 8e93e42f5fd..cf9161c5b7c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -1376,16 +1376,6 @@ static void node_geo_exec(GeoNodeExecParams params) }); params.set_output("Mesh", std::move(geometry_set)); - if (attribute_outputs.top_id) { - params.set_output("Top", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.top_id), params.attribute_producer_name())); - } - if (attribute_outputs.side_id) { - params.set_output("Side", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.side_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_extrude_mesh_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc index 2e256caea4a..1528ee9eb13 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc @@ -836,16 +836,6 @@ static void node_geo_exec(GeoNodeExecParams params) } params.set_output("Curves", std::move(new_curves)); - if (index_attribute_id) { - params.set_output("Closest Index", - AnonymousAttributeFieldInput::Create(std::move(index_attribute_id), - params.attribute_producer_name())); - } - if (weight_attribute_id) { - params.set_output("Closest Weight", - AnonymousAttributeFieldInput::Create( - std::move(weight_attribute_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_interpolate_curves_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 1089f008a59..1d864d5e154 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -851,29 +851,6 @@ static void node_geo_exec(GeoNodeExecParams params) /* Transform the mesh so that the base of the cone is at the origin. */ BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false); - if (attribute_outputs.top_id) { - params.set_output("Top", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.top_id), params.attribute_producer_name())); - } - if (attribute_outputs.bottom_id) { - params.set_output( - "Bottom", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.bottom_id), - params.attribute_producer_name())); - } - if (attribute_outputs.side_id) { - params.set_output("Side", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.side_id), params.attribute_producer_name())); - } - if (attribute_outputs.uv_map_id) { - params.set_output( - "UV Map", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.uv_map_id), - params.attribute_producer_name())); - } - params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index bb615d6315e..06524293d69 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -112,12 +112,6 @@ static void node_geo_exec(GeoNodeExecParams params) Mesh *mesh = create_cube_mesh(size, verts_x, verts_y, verts_z, uv_map_id.get()); params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); - - if (uv_map_id) { - params.set_output("UV Map", - AnonymousAttributeFieldInput::Create( - std::move(uv_map_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_mesh_primitive_cube_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index 5c6f206f04d..37952f8cba0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc @@ -122,29 +122,6 @@ static void node_geo_exec(GeoNodeExecParams params) fill, attribute_outputs); - if (attribute_outputs.top_id) { - params.set_output("Top", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.top_id), params.attribute_producer_name())); - } - if (attribute_outputs.bottom_id) { - params.set_output( - "Bottom", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.bottom_id), - params.attribute_producer_name())); - } - if (attribute_outputs.side_id) { - params.set_output("Side", - AnonymousAttributeFieldInput::Create( - std::move(attribute_outputs.side_id), params.attribute_producer_name())); - } - if (attribute_outputs.uv_map_id) { - params.set_output( - "UV Map", - AnonymousAttributeFieldInput::Create(std::move(attribute_outputs.uv_map_id), - params.attribute_producer_name())); - } - params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 5d9a8c8f2e8..972a451b140 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -205,12 +205,6 @@ static void node_geo_exec(GeoNodeExecParams params) BKE_id_material_eval_ensure_default_slot(&mesh->id); params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); - - if (uv_map_id) { - params.set_output("UV Map", - AnonymousAttributeFieldInput::Create( - std::move(uv_map_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_mesh_primitive_grid_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index 74053462f0e..9d71bd3cf53 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -115,12 +115,6 @@ static void node_geo_exec(GeoNodeExecParams params) Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius, uv_map_id.get()); params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); - - if (uv_map_id) { - params.set_output("UV Map", - AnonymousAttributeFieldInput::Create( - std::move(uv_map_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index f527a413866..0d106669de7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -363,11 +363,6 @@ static void node_geo_exec(GeoNodeExecParams params) Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num, uv_map_id.get()); params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); - if (uv_map_id) { - params.set_output("UV Map", - AnonymousAttributeFieldInput::Create( - std::move(uv_map_id), params.attribute_producer_name())); - } } } // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 6c52af3956f..e9f6f32c76a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -348,9 +348,6 @@ static void create_attributes(GeoNodeExecParams ¶ms, *line_id, ATTR_DOMAIN_INSTANCE); line_attribute.span.copy_from(layout.line_numbers); line_attribute.finish(); - params.set_output("Line", - AnonymousAttributeFieldInput::Create(std::move(line_id), - params.attribute_producer_name())); } if (AnonymousAttributeIDPtr pivot_id = params.get_output_anonymous_attribute_id_if_needed( @@ -363,9 +360,6 @@ static void create_attributes(GeoNodeExecParams ¶ms, } pivot_attribute.finish(); - params.set_output("Pivot Point", - AnonymousAttributeFieldInput::Create( - std::move(pivot_id), params.attribute_producer_name())); } } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 0af6bd940a8..00f4617cf5a 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -21,6 +21,7 @@ #include "BLI_cpp_types.hh" #include "BLI_dot_export.hh" #include "BLI_hash.h" +#include "BLI_hash_md5.h" #include "BLI_lazy_threading.hh" #include "BLI_map.hh" @@ -102,6 +103,43 @@ static void lazy_function_interface_from_node(const bNode &node, } } +/** + * An anonymous attribute created by a node. + */ +class NodeAnonymousAttributeID : public AnonymousAttributeID { + std::string long_name_; + std::string socket_name_; + + public: + NodeAnonymousAttributeID(const Object &object, + const ComputeContext &compute_context, + const bNode &bnode, + const StringRef identifier, + const StringRef name) + : socket_name_(name) + { + const ComputeContextHash &hash = compute_context.hash(); + { + std::stringstream ss; + ss << hash << "_" << object.id.name << "_" << bnode.identifier << "_" << identifier; + long_name_ = ss.str(); + } + { + uint64_t hash_result[2]; + BLI_hash_md5_buffer(long_name_.data(), long_name_.size(), hash_result); + std::stringstream ss; + ss << ".a_" << std::hex << hash_result[0] << hash_result[1]; + name_ = ss.str(); + BLI_assert(name_.size() < MAX_CUSTOMDATA_LAYER_NAME); + } + } + + std::string user_name() const override + { + return socket_name_; + } +}; + /** * Used for most normal geometry nodes like Subdivision Surface and Set Position. */ @@ -117,6 +155,25 @@ class LazyFunctionForGeometryNode : public LazyFunction { * propagated to the output. */ const Span lf_input_for_attribute_propagation_to_output_; + /** + * Maps #bNodeSocket::index_in_tree to input/output indices of the current lazy-function. + */ + const Span lf_index_by_bsocket_; + /** + * A bool for every output bsocket. If true, the socket just outputs a field containing an + * anonymous attribute id. If only such outputs are requested by other nodes, the node itself + * does not have to execute. + */ + Vector is_attribute_output_bsocket_; + + struct OutputAttributeID { + int bsocket_index; + AnonymousAttributeIDPtr attribute_id; + }; + + struct Storage { + Vector attributes; + }; public: LazyFunctionForGeometryNode(const bNode &node, @@ -126,7 +183,9 @@ class LazyFunctionForGeometryNode : public LazyFunction { : node_(node), lf_input_for_output_bsocket_usage_(r_lf_input_for_output_bsocket_usage), lf_input_for_attribute_propagation_to_output_( - r_lf_input_for_attribute_propagation_to_output) + r_lf_input_for_attribute_propagation_to_output), + lf_index_by_bsocket_(r_lf_index_by_bsocket), + is_attribute_output_bsocket_(node.output_sockets().size(), false) { BLI_assert(node.typeinfo->geometry_node_execute != nullptr); debug_name_ = node.name; @@ -137,6 +196,16 @@ class LazyFunctionForGeometryNode : public LazyFunction { if (relations == nullptr) { return; } + if (!relations->available_relations.is_empty()) { + /* Inputs are only used when an output is used that is not just outputting an anonymous + * attribute field. */ + for (lf::Input &input : inputs_) { + input.usage = lf::ValueUsage::Maybe; + } + for (const aal::AvailableRelation &relation : relations->available_relations) { + is_attribute_output_bsocket_[relation.field_output] = true; + } + } Vector handled_field_outputs; for (const aal::AvailableRelation &relation : relations->available_relations) { const bNodeSocket &output_bsocket = node.output_socket(relation.field_output); @@ -160,16 +229,90 @@ class LazyFunctionForGeometryNode : public LazyFunction { } } + void *init_storage(LinearAllocator<> &allocator) const override + { + return allocator.construct().release(); + } + + void destruct_storage(void *storage) const override + { + Storage *s = static_cast(storage); + std::destroy_at(s); + } + void execute_impl(lf::Params ¶ms, const lf::Context &context) const override { + Storage *storage = static_cast(context.storage); GeoNodesLFUserData *user_data = dynamic_cast(context.user_data); BLI_assert(user_data != nullptr); + /* Lazily create the required anonymous attribute ids. */ + auto get_output_attribute_id = [&](const int output_bsocket_index) -> AnonymousAttributeIDPtr { + for (const OutputAttributeID &node_output_attribute : storage->attributes) { + if (node_output_attribute.bsocket_index == output_bsocket_index) { + return node_output_attribute.attribute_id; + } + } + const bNodeSocket &bsocket = node_.output_socket(output_bsocket_index); + AnonymousAttributeIDPtr attribute_id = MEM_new( + __func__, + *user_data->modifier_data->self_object, + *user_data->compute_context, + node_, + bsocket.identifier, + bsocket.name); + storage->attributes.append({output_bsocket_index, attribute_id}); + return attribute_id; + }; + + bool used_non_attribute_output_exists = false; + for (const int output_bsocket_index : node_.output_sockets().index_range()) { + const bNodeSocket &output_bsocket = node_.output_socket(output_bsocket_index); + const int lf_index = lf_index_by_bsocket_[output_bsocket.index_in_tree()]; + if (lf_index == -1) { + continue; + } + const lf::ValueUsage output_usage = params.get_output_usage(lf_index); + if (output_usage == lf::ValueUsage::Unused) { + continue; + } + if (is_attribute_output_bsocket_[output_bsocket_index]) { + if (params.output_was_set(lf_index)) { + continue; + } + this->output_anonymous_attribute_field( + params, lf_index, get_output_attribute_id(output_bsocket_index)); + } + else { + if (output_usage == lf::ValueUsage::Used) { + used_non_attribute_output_exists = true; + } + } + } + + if (!used_non_attribute_output_exists) { + /* Only attribute outputs are used currently, no need to evaluate the full node and its + * inputs. */ + return; + } + + bool missing_input = false; + for (const int lf_index : inputs_.index_range()) { + if (params.try_get_input_data_ptr_or_request(lf_index) == nullptr) { + missing_input = true; + } + } + if (missing_input) { + /* Wait until all inputs are available. */ + return; + } + GeoNodeExecParams geo_params{node_, params, context, lf_input_for_output_bsocket_usage_, - lf_input_for_attribute_propagation_to_output_}; + lf_input_for_attribute_propagation_to_output_, + get_output_attribute_id}; geo_eval_log::TimePoint start_time = geo_eval_log::Clock::now(); node_.typeinfo->geometry_node_execute(geo_params); @@ -182,6 +325,24 @@ class LazyFunctionForGeometryNode : public LazyFunction { } } + /** + * Output the given anonymous attribute id as a field. + */ + void output_anonymous_attribute_field(lf::Params ¶ms, + const int lf_index, + AnonymousAttributeIDPtr attribute_id) const + { + const ValueOrFieldCPPType &value_or_field_cpp_type = *ValueOrFieldCPPType::get_from_self( + *outputs_[lf_index].type); + GField output_field{ + std::make_shared(std::move(attribute_id), + value_or_field_cpp_type.value, + node_.label_or_name() + TIP_(" node"))}; + void *r_value = params.get_output_data_ptr(lf_index); + value_or_field_cpp_type.construct_from_field(r_value, std::move(output_field)); + params.output_set(lf_index); + } + std::string input_name(const int index) const override { for (const bNodeSocket *bsocket : node_.output_sockets()) { diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 66c2dbf8547..a7caed7042b 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -9,40 +9,10 @@ #include "NOD_geometry_exec.hh" -#include "BLI_hash_md5.h" - #include "node_geometry_util.hh" namespace blender::nodes { -NodeAnonymousAttributeID::NodeAnonymousAttributeID(const Object &object, - const ComputeContext &compute_context, - const bNode &bnode, - const StringRef identifier, - const StringRef name) - : socket_name_(name) -{ - const ComputeContextHash &hash = compute_context.hash(); - { - std::stringstream ss; - ss << hash << "_" << object.id.name << "_" << bnode.identifier << "_" << identifier; - long_name_ = ss.str(); - } - { - uint64_t hash_result[2]; - BLI_hash_md5_buffer(long_name_.data(), long_name_.size(), hash_result); - std::stringstream ss; - ss << ".a_" << std::hex << hash_result[0] << hash_result[1]; - name_ = ss.str(); - BLI_assert(name_.size() < MAX_CUSTOMDATA_LAYER_NAME); - } -} - -std::string NodeAnonymousAttributeID::user_name() const -{ - return socket_name_; -} - void GeoNodeExecParams::error_message_add(const NodeWarningType type, const StringRef message) const { @@ -153,11 +123,6 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -std::string GeoNodeExecParams::attribute_producer_name() const -{ - return node_.label_or_name() + TIP_(" node"); -} - void GeoNodeExecParams::set_default_remaining_outputs() { params_.set_default_remaining_outputs();