[Bf-blender-cvs] [2ffd08e9524] master: Geometry Nodes: deterministic anonymous attribute lifetimes

Jacques Lucke noreply at git.blender.org
Thu Jan 5 14:09:43 CET 2023


Commit: 2ffd08e95249df2a068dd400cd3117cf8ca4a246
Author: Jacques Lucke
Date:   Thu Jan 5 14:05:30 2023 +0100
Branches: master
https://developer.blender.org/rB2ffd08e95249df2a068dd400cd3117cf8ca4a246

Geometry Nodes: deterministic anonymous attribute lifetimes

Previously, the lifetimes of anonymous attributes were determined by
reference counts which were non-deterministic when multiple threads
are used. Now the lifetimes of anonymous attributes are handled
more explicitly and deterministically. This is a prerequisite for any kind
of caching, because caching the output of nodes that do things
non-deterministically and have "invisible inputs" (reference counts)
doesn't really work.

For more details for how deterministic lifetimes are achieved, see D16858.

No functional changes are expected. Small performance changes are expected
as well (within few percent, anything larger regressions should be reported as
bugs).

Differential Revision: https://developer.blender.org/D16858

===================================================================

D	source/blender/blenkernel/BKE_anonymous_attribute.h
D	source/blender/blenkernel/BKE_anonymous_attribute.hh
A	source/blender/blenkernel/BKE_anonymous_attribute_id.hh
M	source/blender/blenkernel/BKE_attribute.hh
M	source/blender/blenkernel/BKE_curve_to_mesh.hh
M	source/blender/blenkernel/BKE_curves.hh
M	source/blender/blenkernel/BKE_customdata.h
M	source/blender/blenkernel/BKE_geometry_fields.hh
M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/BKE_instances.hh
M	source/blender/blenkernel/BKE_node_runtime.hh
M	source/blender/blenkernel/CMakeLists.txt
D	source/blender/blenkernel/intern/anonymous_attribute.cc
A	source/blender/blenkernel/intern/anonymous_attribute_id.cc
M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/blenkernel/intern/attribute_access_intern.hh
M	source/blender/blenkernel/intern/cpp_types.cc
M	source/blender/blenkernel/intern/curve_to_mesh_convert.cc
M	source/blender/blenkernel/intern/curves_geometry.cc
M	source/blender/blenkernel/intern/customdata.cc
M	source/blender/blenkernel/intern/geometry_component_mesh.cc
M	source/blender/blenkernel/intern/geometry_fields.cc
M	source/blender/blenkernel/intern/geometry_set.cc
M	source/blender/blenkernel/intern/instances.cc
M	source/blender/blenkernel/intern/mesh_convert.cc
M	source/blender/blenkernel/intern/node.cc
A	source/blender/blenkernel/intern/node_tree_anonymous_attributes.cc
M	source/blender/blenkernel/intern/node_tree_update.cc
M	source/blender/editors/mesh/mesh_data.cc
M	source/blender/functions/FN_lazy_function_graph.hh
M	source/blender/functions/intern/lazy_function_graph.cc
M	source/blender/geometry/GEO_fillet_curves.hh
M	source/blender/geometry/GEO_mesh_split_edges.hh
M	source/blender/geometry/GEO_mesh_to_curve.hh
M	source/blender/geometry/GEO_point_merge_by_distance.hh
M	source/blender/geometry/GEO_realize_instances.hh
M	source/blender/geometry/GEO_resample_curves.hh
M	source/blender/geometry/GEO_set_curve_type.hh
M	source/blender/geometry/GEO_subdivide_curves.hh
M	source/blender/geometry/GEO_trim_curves.hh
M	source/blender/geometry/intern/add_curves_on_mesh.cc
M	source/blender/geometry/intern/fillet_curves.cc
M	source/blender/geometry/intern/mesh_split_edges.cc
M	source/blender/geometry/intern/mesh_to_curve_convert.cc
M	source/blender/geometry/intern/point_merge_by_distance.cc
M	source/blender/geometry/intern/realize_instances.cc
M	source/blender/geometry/intern/resample_curves.cc
M	source/blender/geometry/intern/set_curve_type.cc
M	source/blender/geometry/intern/subdivide_curves.cc
M	source/blender/geometry/intern/trim_curves.cc
M	source/blender/makesdna/DNA_customdata_types.h
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/nodes/NOD_geometry_exec.hh
M	source/blender/nodes/NOD_geometry_nodes_lazy_function.hh
M	source/blender/nodes/geometry/node_geometry_util.hh
M	source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
M	source/blender/nodes/geometry/nodes/node_geo_boolean.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
M	source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
M	source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
M	source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc
M	source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
M	source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
M	source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
M	source/blender/nodes/intern/geometry_nodes_lazy_function.cc
M	source/blender/nodes/intern/geometry_nodes_log.cc
M	source/blender/nodes/intern/node_geometry_exec.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_anonymous_attribute.h b/source/blender/blenkernel/BKE_anonymous_attribute.h
deleted file mode 100644
index ab26f2c6224..00000000000
--- a/source/blender/blenkernel/BKE_anonymous_attribute.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-/** \file
- * \ingroup bke
- *
- * An #AnonymousAttributeID is used to identify attributes that are not explicitly named.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct AnonymousAttributeID AnonymousAttributeID;
-
-AnonymousAttributeID *BKE_anonymous_attribute_id_new_weak(const char *debug_name);
-AnonymousAttributeID *BKE_anonymous_attribute_id_new_strong(const char *debug_name);
-bool BKE_anonymous_attribute_id_has_strong_references(const AnonymousAttributeID *anonymous_id);
-void BKE_anonymous_attribute_id_increment_weak(const AnonymousAttributeID *anonymous_id);
-void BKE_anonymous_attribute_id_increment_strong(const AnonymousAttributeID *anonymous_id);
-void BKE_anonymous_attribute_id_decrement_weak(const AnonymousAttributeID *anonymous_id);
-void BKE_anonymous_attribute_id_decrement_strong(const AnonymousAttributeID *anonymous_id);
-const char *BKE_anonymous_attribute_id_debug_name(const AnonymousAttributeID *anonymous_id);
-const char *BKE_anonymous_attribute_id_internal_name(const AnonymousAttributeID *anonymous_id);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/blenkernel/BKE_anonymous_attribute.hh b/source/blender/blenkernel/BKE_anonymous_attribute.hh
deleted file mode 100644
index d9161bda572..00000000000
--- a/source/blender/blenkernel/BKE_anonymous_attribute.hh
+++ /dev/null
@@ -1,155 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-#include <atomic>
-#include <string>
-
-#include "BLI_hash.hh"
-#include "BLI_string_ref.hh"
-
-#include "BKE_anonymous_attribute.h"
-
-namespace blender::bke {
-
-/**
- * Wrapper for #AnonymousAttributeID with RAII semantics.
- * This class should typically not be used directly. Instead use #StrongAnonymousAttributeID or
- * #WeakAnonymousAttributeID.
- */
-template<bool IsStrongReference> class OwnedAnonymousAttributeID {
- private:
-  const AnonymousAttributeID *data_ = nullptr;
-
-  template<bool OtherIsStrongReference> friend class OwnedAnonymousAttributeID;
-
- public:
-  OwnedAnonymousAttributeID() = default;
-
-  /** Create a new anonymous attribute id. */
-  explicit OwnedAnonymousAttributeID(StringRefNull debug_name)
-  {
-    if constexpr (IsStrongReference) {
-      data_ = BKE_anonymous_attribute_id_new_strong(debug_name.c_str());
-    }
-    else {
-      data_ = BKE_anonymous_attribute_id_new_weak(debug_name.c_str());
-    }
-  }
-
-  /**
-   * This transfers ownership, so no incref is necessary.
-   * The caller has to make sure that it owned the anonymous id.
-   */
-  explicit OwnedAnonymousAttributeID(const AnonymousAttributeID *anonymous_id)
-      : data_(anonymous_id)
-  {
-  }
-
-  template<bool OtherIsStrong>
-  OwnedAnonymousAttributeID(const OwnedAnonymousAttributeID<OtherIsStrong> &other)
-  {
-    data_ = other.data_;
-    this->incref();
-  }
-
-  template<bool OtherIsStrong>
-  OwnedAnonymousAttributeID(OwnedAnonymousAttributeID<OtherIsStrong> &&other)
-  {
-    data_ = other.data_;
-    this->incref();
-    other.decref();
-    other.data_ = nullptr;
-  }
-
-  ~OwnedAnonymousAttributeID()
-  {
-    this->decref();
-  }
-
-  template<bool OtherIsStrong>
-  OwnedAnonymousAttributeID &operator=(const OwnedAnonymousAttributeID<OtherIsStrong> &other)
-  {
-    if (this == &other) {
-      return *this;
-    }
-    this->~OwnedAnonymousAttributeID();
-    new (this) OwnedAnonymousAttributeID(other);
-    return *this;
-  }
-
-  template<bool OtherIsStrong>
-  OwnedAnonymousAttributeID &operator=(OwnedAnonymousAttributeID<OtherIsStrong> &&other)
-  {
-    if (this == &other) {
-      return *this;
-    }
-    this->~OwnedAnonymousAttributeID();
-    new (this) OwnedAnonymousAttributeID(std::move(other));
-    return *this;
-  }
-
-  operator bool() const
-  {
-    return data_ != nullptr;
-  }
-
-  StringRefNull debug_name() const
-  {
-    BLI_assert(data_ != nullptr);
-    return BKE_anonymous_attribute_id_debug_name(data_);
-  }
-
-  bool has_strong_references() const
-  {
-    BLI_assert(data_ != nullptr);
-    return BKE_anonymous_attribute_id_has_strong_references(data_);
-  }
-
-  /** Extract the ownership of the currently wrapped anonymous id. */
-  const AnonymousAttributeID *extract()
-  {
-    const AnonymousAttributeID *extracted_data = data_;
-    /* Don't decref because the caller becomes the new owner. */
-    data_ = nullptr;
-    return extracted_data;
-  }
-
-  /** Get the wrapped anonymous id, without taking ownership. */
-  const AnonymousAttributeID *get() const
-  {
-    return data_;
-  }
-
- private:
-  void incref()
-  {
-    if (data_ == nullptr) {
-      return;
-    }
-    if constexpr (IsStrongReference) {
-      BKE_anonymous_attribute_id_increment_strong(data_);
-    }
-    else {
-      BKE_anonymous_attribute_id_increment_weak(data_);
-    }
-  }
-
-  void decref()
-  {
-    if (data_ == nullptr) {
-      return;
-    }
-    if constexpr (IsStrongReference) {
-      BKE_anonymous_attribute_id_decrement_strong(data_);
-    }
-    else {
-      BKE_anonymous_attribute_id_decrement_weak(data_);
-    }
-  }
-};
-
-using StrongAnonymousAttributeID = OwnedAnonymousAttributeID<true>;
-using WeakAnonymousAttributeID = OwnedAnonymousAttributeID<false>;
-
-}  // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_anonymous_attribute_id.hh b/source/blender/blenkernel/BKE_anonymous_attribute_id.hh
new file mode 100644
index 00000000000..f9b6e2ca543
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anonymous_attribute_id.hh
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <atomic>
+
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_user_counter.hh"
+
+namespace blender::bke {
+
+/**
+ * An #AnonymousAttributeID contains information about a specific anonymous attribute.
+ * Like normal attributes, anonymous attributes are also identified by their name, so one should
+ * not have to compare #AnonymousAttributeID pointers.
+ *
+ * Anonymous attributes don't need additional information besides their name, with a few
+ * exceptions:
+ * - The name of anonymous attributes is generated automatically, so it is generally not human
+ *   readable (just random characters). #AnonymousAttributeID can provide more context as where a
+ *   specific anonymous attribute was created which can simplify debugging.
+ * - [Not yet supported.] When anonymous attributes are contained in on-disk caches, we have to map
+ *   those back to anonymous attributes at run-time. The issue is that (for various reasons) we
+ *   might change how anonymous attribute names are generated in the future, which would lead to a
+ *   mis-match between stored and new attribute names. To work around it, we should cache
+ *   additional information for anonymous attributes on disk (like which node created it). This
+ *   information can then be used to map stored attributes to their run-time counterpart.
+ *
+ * Once created, #AnonymousAttributeID is immutable. Also it is intrinsicly reference counted so
+ * that it can have shared ownership. `std::shared_ptr` can't be used for that purpose here,
+ * because that is not available in C code. If possible, the #AutoAnonymousAttributeID wrapper
+ * should be used to avoid manual reference counting in C++ code.
+ */
+class AnonymousAttributeID {
+ private:
+  mutable std::atomic<int> users_ = 1;
+
+ protected:
+  std::string name_;
+
+ public:
+  virtual ~AnonymousAttributeID() = default;
+
+  StringRefNull name() const
+  {
+    return name_;
+  }
+
+  void user_add() const
+  {
+    users_.fetch_add(1);
+  }
+
+  void user_remove() const
+  {
+    const int new_users = users_.fetch_sub(1) - 1;
+    if (new_users == 0) {
+      MEM_delete(this);
+    }
+  }
+};
+
+/** Wrapper for #AnonymousAttributeID that avoids manual reference counting. */
+using AutoAnonymousAttributeID = UserCounter<const AnonymousAttributeID>;
+
+/**
+ * A set of anonymous attribute names that is passed around in geometry nodes.
+ */
+class AnonymousAttributeSet {
+ public:
+  /**
+   * This uses `std::shared_ptr` because attributes sets are passed around by value during geometry
+   * nodes evaluation, and this makes it very small if there is no name. Also it makes copying very
+   * cheap.
+   */
+  std::shared_ptr<Set<std::string>> names;
+};
+
+/**
+ * Can be passed to algorithms which propagate attributes. It can tell the algorithm which
+ * anonymous attributes should be propagated and can be skipped.
+ */
+class AnonymousAttributePropagationInfo {
+ public:
+  /**
+   * This uses `std::shared_ptr` because it's usually initialized from an #AnonymousAttributeSet
+   * and then the set doesn't have to be copied.
+   */
+  std::shared_ptr<Set<std::string>> names;
+
+  /**
+   * Propagate all anonymous attributes even if the set above is empty.
+   */
+  bool propagate_all = true;
+
+  /**
+   * Return true when the anonymous attribute should be propagated and false otherwise.
+   */
+  bool propagate(const AnonymousAttributeID &anonymous_id) const;
+};
+
+}  // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index a4f9d73c31e..031a4bb86ea 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -11,7 +11,7 @@
 #include "BLI_math_vec_types.hh"
 #include "BLI_set.hh"
 
-#include "BKE_anonymous_attribute.hh"
+#include "BKE_anonymous_attribute_id.hh"
 #include "BKE_attribute.h"
 
 struct Mesh;
@@ -24,7 +24,7 @@ class GField;
 namespace blender::bke {
 
 /**
- * Identifies an attribute that is either named or anonymous.
+ * Identifies an attribute with optional anonymous attribute information.
  * It does not own the identifier, so it is just a reference.
  */
 class AttributeIDRef {
@@ -38,15 +38,14 @@ class AttributeIDRef {
   AttributeIDRef(StringRefNull name);
   AttributeIDRef(const char *name);

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list