[Bf-blender-cvs] [74979459cbb] master: Geometry Nodes: simplify allocating dynamically sized buffer on stack

Jacques Lucke noreply at git.blender.org
Sun Mar 7 17:54:29 CET 2021


Commit: 74979459cbbe4ec5bf7014a511775b5274b20060
Author: Jacques Lucke
Date:   Sun Mar 7 17:51:56 2021 +0100
Branches: master
https://developer.blender.org/rB74979459cbbe4ec5bf7014a511775b5274b20060

Geometry Nodes: simplify allocating dynamically sized buffer on stack

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

M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/blenlib/BLI_memory_utils.hh
M	source/blender/functions/FN_cpp_type.hh

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

diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 61dc0903cc8..b04af5327ca 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -438,9 +438,6 @@ class ConvertedReadAttribute final : public ReadAttribute {
   ReadAttributePtr base_attribute_;
   const nodes::DataTypeConversions &conversions_;
 
-  static constexpr int MaxValueSize = 64;
-  static constexpr int MaxValueAlignment = 64;
-
  public:
   ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
       : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
@@ -449,17 +446,13 @@ class ConvertedReadAttribute final : public ReadAttribute {
         base_attribute_(std::move(base_attribute)),
         conversions_(nodes::get_implicit_type_conversions())
   {
-    if (from_type_.size() > MaxValueSize || from_type_.alignment() > MaxValueAlignment) {
-      throw std::runtime_error(
-          "type is larger than expected, the buffer size has to be increased");
-    }
   }
 
   void get_internal(const int64_t index, void *r_value) const override
   {
-    AlignedBuffer<MaxValueSize, MaxValueAlignment> buffer;
-    base_attribute_->get(index, buffer.ptr());
-    conversions_.convert(from_type_, to_type_, buffer.ptr(), r_value);
+    BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+    base_attribute_->get(index, buffer);
+    conversions_.convert(from_type_, to_type_, buffer, r_value);
   }
 };
 
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index b3b6855089e..bdbbda9f0c7 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -28,6 +28,7 @@
 #include <type_traits>
 
 #include "BLI_utildefines.h"
+#include "MEM_guardedalloc.h"
 
 namespace blender {
 
@@ -402,6 +403,50 @@ template<typename T, int64_t Size = 1> class TypedBuffer {
   }
 };
 
+/* A dynamic stack buffer can be used instead of #alloca when wants to allocate a dynamic amount of
+ * memory on the stack. Using this class has some advantages:
+ *  - It falls back to heap allocation, when the size is too large.
+ *  - It can be used in loops safely.
+ *  - If the buffer is heap allocated, it is free automatically in the destructor.
+ */
+template<size_t ReservedSize = 64, size_t ReservedAlignment = 64>
+class alignas(ReservedAlignment) DynamicStackBuffer {
+ private:
+  /* Don't create an empty array. This causes problems with some compilers. */
+  char reserved_buffer_[(ReservedSize > 0) ? ReservedSize : 1];
+  void *buffer_;
+
+ public:
+  DynamicStackBuffer(const int64_t size, const int64_t alignment)
+  {
+    BLI_assert(size >= 0);
+    BLI_assert(alignment >= 0);
+    if (size <= ReservedSize && alignment <= ReservedAlignment) {
+      buffer_ = reserved_buffer_;
+    }
+    else {
+      buffer_ = MEM_mallocN_aligned(size, alignment, __func__);
+    }
+  }
+  ~DynamicStackBuffer()
+  {
+    if (buffer_ != reserved_buffer_) {
+      MEM_freeN(buffer_);
+    }
+  }
+
+  /* Don't allow any copying or moving of this type. */
+  DynamicStackBuffer(const DynamicStackBuffer &other) = delete;
+  DynamicStackBuffer(DynamicStackBuffer &&other) = delete;
+  DynamicStackBuffer &operator=(const DynamicStackBuffer &other) = delete;
+  DynamicStackBuffer &operator=(DynamicStackBuffer &&other) = delete;
+
+  void *buffer() const
+  {
+    return buffer_;
+  }
+};
+
 /**
  * This can be used by container constructors. A parameter of this type should be used to indicate
  * that the constructor does not construct the elements.
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index a854e63288d..b8ac97d6dbd 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -935,3 +935,9 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
   { \
     return blender::fn::CPPType::get<TYPE_NAME>(); \
   }
+
+/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */
+#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \
+  blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name(type.size(), \
+                                                                       type.alignment()); \
+  void *variable_name = stack_buffer_for_##variable_name.buffer();



More information about the Bf-blender-cvs mailing list