Geometry Nodes: simplify allocating dynamically sized buffer on stack
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user