[Bf-blender-cvs] [2cda65a35a6] master: Geometry Nodes: avoid allocation when construct varray for single value

Jacques Lucke noreply at git.blender.org
Fri Nov 26 09:59:54 CET 2021


Commit: 2cda65a35a61e0bb74f4b2b896feede73c329b59
Author: Jacques Lucke
Date:   Fri Nov 26 09:59:41 2021 +0100
Branches: master
https://developer.blender.org/rB2cda65a35a61e0bb74f4b2b896feede73c329b59

Geometry Nodes: avoid allocation when construct varray for single value

Previously, `GVArray::ForSingle` would always allocate a copy of the passed
in value. Now it only does so when the value is too large or not trivial.

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

M	source/blender/functions/FN_cpp_type.hh
M	source/blender/functions/intern/generic_virtual_array.cc

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

diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 643b2fc1f28..7ddb5bf1f46 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -207,6 +207,18 @@ class CPPType : NonCopyable, NonMovable {
     return is_trivially_destructible_;
   }
 
+  /**
+   * When true, the value is like a normal C type, it can be copied around with #memcpy and does
+   * not have to be destructed.
+   *
+   * C++ equivalent:
+   *   std::is_trivial_v<T>;
+   */
+  bool is_trivial() const
+  {
+    return is_trivial_;
+  }
+
   bool is_default_constructible() const
   {
     return default_construct_ != nullptr;
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index 9df48818766..160234c6e61 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -336,6 +336,57 @@ class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef,
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SmallTrivialSingleValue
+ * \{ */
+
+/**
+ * Contains an inline buffer that can store a single value of a trivial type.
+ * This avoids the allocation that would be done by #GVArrayImpl_For_SingleValue.
+ */
+template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public GVArrayImpl {
+ private:
+  AlignedBuffer<BufferSize, 8> buffer_;
+
+ public:
+  GVArrayImpl_For_SmallTrivialSingleValue(const CPPType &type,
+                                          const int64_t size,
+                                          const void *value)
+      : GVArrayImpl(type, size)
+  {
+    BLI_assert(type.is_trivial());
+    BLI_assert(type.alignment() <= 8);
+    BLI_assert(type.size() <= BufferSize);
+    type.copy_construct(value, &buffer_);
+  }
+
+ private:
+  void get(const int64_t UNUSED(index), void *r_value) const override
+  {
+    this->copy_value_to(r_value);
+  }
+  void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
+  {
+    this->copy_value_to(r_value);
+  }
+
+  bool is_single() const override
+  {
+    return true;
+  }
+  void get_internal_single(void *r_value) const override
+  {
+    this->copy_value_to(r_value);
+  }
+
+  void copy_value_to(void *dst) const
+  {
+    memcpy(dst, &buffer_, type_->size());
+  }
+};
+
+/** \} */
+
 /* -------------------------------------------------------------------- */
 /** \name #GVArray_GSpan
  * \{ */
@@ -593,6 +644,9 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m
 
 GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
 {
+  if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) {
+    return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
+  }
   return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
 }



More information about the Bf-blender-cvs mailing list