diff options
author | Jacques Lucke <jacques@blender.org> | 2021-11-26 11:59:41 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-11-26 11:59:41 +0300 |
commit | 2cda65a35a61e0bb74f4b2b896feede73c329b59 (patch) | |
tree | 9d9460de93f1dd021b4bc36d2c78776b2f782a9c /source/blender/functions | |
parent | 8015433f81b4956e4ee4efffb80ab10324df5675 (diff) |
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.
Diffstat (limited to 'source/blender/functions')
-rw-r--r-- | source/blender/functions/FN_cpp_type.hh | 12 | ||||
-rw-r--r-- | source/blender/functions/intern/generic_virtual_array.cc | 54 |
2 files changed, 66 insertions, 0 deletions
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 @@ -337,6 +337,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); } |