[Bf-blender-cvs] [1713a780c56] temp-copy-on-write: progress

Jacques Lucke noreply at git.blender.org
Tue Jan 4 13:38:16 CET 2022


Commit: 1713a780c56b1c2fc1ba3e1b02fc6f860cd2604b
Author: Jacques Lucke
Date:   Mon Jan 3 16:55:45 2022 +0100
Branches: temp-copy-on-write
https://developer.blender.org/rB1713a780c56b1c2fc1ba3e1b02fc6f860cd2604b

progress

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

M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/intern/geometry_set.cc
M	source/blender/blenlib/BLI_copy_on_write.h
M	source/blender/blenlib/intern/copy_on_write.cc
M	source/blender/geometry/intern/realize_instances.cc

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

diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 0f9c2c1062b..b3e757a83ba 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -23,6 +23,7 @@
 #include <atomic>
 #include <iostream>
 
+#include "BLI_copy_on_write.h"
 #include "BLI_float3.hh"
 #include "BLI_float4x4.hh"
 #include "BLI_function_ref.hh"
@@ -63,14 +64,13 @@ class GeometryComponent;
 
 /**
  * This is the base class for specialized geometry component types. A geometry component handles
- * a user count to allow avoiding duplication when it is wrapped with #UserCounter. It also handles
- * the attribute API, which generalizes storing and modifying generic information on a geometry.
+ * a user count to allow avoiding duplication when it is wrapped with #bCopyOnWrite. It also
+ * handles the attribute API, which generalizes storing and modifying generic information on a
+ * geometry.
  */
 class GeometryComponent {
  private:
-  /* The reference count has two purposes. When it becomes zero, the component is freed. When it is
-   * larger than one, the component becomes immutable. */
-  mutable std::atomic<int> users_ = 1;
+  blender::bCopyOnWrite cow_;
   GeometryComponentType type_;
 
  public:
@@ -81,14 +81,22 @@ class GeometryComponent {
   /* The returned component should be of the same type as the type this is called on. */
   virtual GeometryComponent *copy() const = 0;
 
+  const blender::bCopyOnWrite &cow() const
+  {
+    return cow_;
+  }
+
+  void cow_delete_self() const
+  {
+    delete this;
+  }
+
   /* Direct data is everything except for instances of objects/collections.
    * If this returns true, the geometry set can be cached and is still valid after e.g. modifier
    * evaluation ends. Instances can only be valid as long as the data they instance is valid. */
   virtual bool owns_direct_data() const = 0;
   virtual void ensure_owns_direct_data() = 0;
 
-  void user_add() const;
-  void user_remove() const;
   bool is_mutable() const;
 
   GeometryComponentType type() const;
@@ -310,7 +318,7 @@ inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryCompon
  */
 struct GeometrySet {
  private:
-  using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
+  using GeometryComponentPtr = blender::COWUser<class GeometryComponent>;
   /* Indexed by #GeometryComponentType. */
   std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
 
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 06e0e78745b..5defda3aa63 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -69,24 +69,9 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
   return nullptr;
 }
 
-void GeometryComponent::user_add() const
-{
-  users_.fetch_add(1);
-}
-
-void GeometryComponent::user_remove() const
-{
-  const int new_users = users_.fetch_sub(1) - 1;
-  if (new_users == 0) {
-    delete this;
-  }
-}
-
 bool GeometryComponent::is_mutable() const
 {
-  /* If the item is shared, it is read-only. */
-  /* The user count can be 0, when this is called from the destructor. */
-  return users_ <= 1;
+  return cow_.is_mutable();
 }
 
 GeometryComponentType GeometryComponent::type() const
@@ -168,7 +153,7 @@ void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component
 void GeometrySet::add(const GeometryComponent &component)
 {
   BLI_assert(!components_[component.type()]);
-  component.user_add();
+  component.cow().user_add();
   components_[component.type()] = const_cast<GeometryComponent *>(&component);
 }
 
diff --git a/source/blender/blenlib/BLI_copy_on_write.h b/source/blender/blenlib/BLI_copy_on_write.h
index 838d4c38b0e..e1dba871207 100644
--- a/source/blender/blenlib/BLI_copy_on_write.h
+++ b/source/blender/blenlib/BLI_copy_on_write.h
@@ -20,7 +20,9 @@
  * \ingroup bli
  */
 
+#include "BLI_assert.h"
 #include "BLI_compiler_attrs.h"
+#include "BLI_utility_mixins.hh"
 
 #include "DNA_copy_on_write.h"
 
@@ -31,11 +33,10 @@ extern "C" {
 bCopyOnWrite *BLI_cow_new(int user_count);
 void BLI_cow_free(const bCopyOnWrite *cow);
 
-void BLI_cow_init(const bCopyOnWrite *cow, int user_count);
+void BLI_cow_init(const bCopyOnWrite *cow);
 
 bool BLI_cow_is_shared(const bCopyOnWrite *cow);
 bool BLI_cow_is_mutable(const bCopyOnWrite *cow);
-bool BLI_cow_is_zero(const bCopyOnWrite *cow);
 
 void BLI_cow_user_add(const bCopyOnWrite *cow);
 bool BLI_cow_user_remove(const bCopyOnWrite *cow) ATTR_WARN_UNUSED_RESULT;
@@ -43,3 +44,179 @@ bool BLI_cow_user_remove(const bCopyOnWrite *cow) ATTR_WARN_UNUSED_RESULT;
 #ifdef __cplusplus
 }
 #endif
+
+#ifdef __cplusplus
+
+namespace blender {
+
+class bCopyOnWrite : public ::bCopyOnWrite, private NonCopyable, NonMovable {
+ public:
+  bCopyOnWrite()
+  {
+    BLI_cow_init(this);
+  }
+
+  ~bCopyOnWrite()
+  {
+    BLI_assert(this->is_mutable());
+  }
+
+  bool is_shared() const
+  {
+    return BLI_cow_is_shared(this);
+  }
+
+  bool is_mutable() const
+  {
+    return BLI_cow_is_mutable(this);
+  }
+
+  void user_add() const
+  {
+    BLI_cow_user_add(this);
+  }
+
+  bool user_remove() const ATTR_WARN_UNUSED_RESULT
+  {
+    return BLI_cow_user_remove(this);
+  }
+};
+
+template<typename T> class COWUser {
+ private:
+  T *data_ = nullptr;
+
+ public:
+  COWUser() = default;
+
+  COWUser(T *data) : data_(data)
+  {
+  }
+
+  COWUser(const COWUser &other) : data_(other.data_)
+  {
+    this->user_add(data_);
+  }
+
+  COWUser(COWUser &&other) : data_(other.data_)
+  {
+    other.data_ = nullptr;
+  }
+
+  ~COWUser()
+  {
+    this->user_remove(data_);
+  }
+
+  COWUser &operator=(const COWUser &other)
+  {
+    if (this == &other) {
+      return *this;
+    }
+
+    this->user_remove(data_);
+    data_ = other.data_;
+    this->user_add(data_);
+    return *this;
+  }
+
+  COWUser &operator=(COWUser &&other)
+  {
+    if (this == &other) {
+      return *this;
+    }
+
+    this->user_remove(data_);
+    data_ = other.data_;
+    other.data_ = nullptr;
+    return *this;
+  }
+
+  T *operator->()
+  {
+    BLI_assert(data_ != nullptr);
+    return data_;
+  }
+
+  const T *operator->() const
+  {
+    BLI_assert(data_ != nullptr);
+    return data_;
+  }
+
+  T &operator*()
+  {
+    BLI_assert(data_ != nullptr);
+    return *data_;
+  }
+
+  const T &operator*() const
+  {
+    BLI_assert(data_ != nullptr);
+    return *data_;
+  }
+
+  operator bool() const
+  {
+    return data_ != nullptr;
+  }
+
+  T *get()
+  {
+    return data_;
+  }
+
+  const T *get() const
+  {
+    return data_;
+  }
+
+  T *release()
+  {
+    T *data = data_;
+    data_ = nullptr;
+    return data;
+  }
+
+  void reset()
+  {
+    this->user_remove(data_);
+    data_ = nullptr;
+  }
+
+  bool has_value() const
+  {
+    return data_ != nullptr;
+  }
+
+  uint64_t hash() const
+  {
+    return get_default_hash(data_);
+  }
+
+  friend bool operator==(const COWUser &a, const COWUser &b)
+  {
+    return a.data_ == b.data_;
+  }
+
+ private:
+  static void user_add(T *data)
+  {
+    if (data != nullptr) {
+      data->cow().user_add();
+    }
+  }
+
+  static void user_remove(T *data)
+  {
+    if (data != nullptr) {
+      if (data->cow().user_remove()) {
+        data->cow_delete_self();
+      }
+    }
+  }
+};
+
+}  // namespace blender
+
+#endif
diff --git a/source/blender/blenlib/intern/copy_on_write.cc b/source/blender/blenlib/intern/copy_on_write.cc
index c1fc7a7569b..4479db326b2 100644
--- a/source/blender/blenlib/intern/copy_on_write.cc
+++ b/source/blender/blenlib/intern/copy_on_write.cc
@@ -44,9 +44,9 @@ void BLI_cow_free(const bCopyOnWrite *cow)
   MEM_freeN(const_cast<bCopyOnWrite *>(cow));
 }
 
-void BLI_cow_init(const bCopyOnWrite *cow, int user_count)
+void BLI_cow_init(const bCopyOnWrite *cow)
 {
-  get_counter(cow) = user_count;
+  get_counter(cow) = 1;
 }
 
 bool BLI_cow_is_mutable(const bCopyOnWrite *cow)
@@ -59,11 +59,6 @@ bool BLI_cow_is_shared(const bCopyOnWrite *cow)
   return cow->user_count >= 2;
 }
 
-bool BLI_cow_is_zero(const bCopyOnWrite *cow)
-{
-  return cow->user_count == 0;
-}
-
 void BLI_cow_user_add(const bCopyOnWrite *cow)
 {
   atomic_fetch_and_add_int32(&get_counter(cow), 1);
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index 4022794d53f..16f0db3f430 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -191,7 +191,7 @@ struct GatherTasks {
 
   /* Volumes only have very simple support currently. Only the first found volume is put into the
    * output. */
-  UserCounter<VolumeComponent> first_volume;
+  COWUser<VolumeComponent> first_volume;
 };
 
 /** Current offsets while during the gather operation. */
@@ -480,7 +480,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
       case GEO_COMPONENT_TYPE_VOLUME: {
         const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
         if (!gather_info.r_tasks.first_volume) {
-          volume_component->user_add();
+          volume_component->cow().user_add();
           gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
         }
         break;



More information about the Bf-blender-cvs mailing list