diff options
author | Jacques Lucke <jacques@blender.org> | 2021-03-07 19:51:56 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-03-07 19:53:05 +0300 |
commit | 74979459cbbe4ec5bf7014a511775b5274b20060 (patch) | |
tree | 14b2e0ecb04ca2a063f9ff83b192b72e405ca5cc | |
parent | 9c8382e6186b519429e4dee8870265351810bc99 (diff) |
Geometry Nodes: simplify allocating dynamically sized buffer on stack
-rw-r--r-- | source/blender/blenkernel/intern/attribute_access.cc | 13 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_memory_utils.hh | 45 | ||||
-rw-r--r-- | source/blender/functions/FN_cpp_type.hh | 6 |
3 files changed, 54 insertions, 10 deletions
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(); |