From 602ecbdf9aef58a4e3c8d7ea5db22a913bf60525 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 26 Nov 2021 15:33:21 +0100 Subject: Geometry Nodes: optimize Set Position node This implements four optimizations in the Set Position node: * Check whether the position input is the current position and ignore it if it is. This results in a speedup when only the Offset input is used. * Use multi-threading when copying to computed values to the position attribute. All geometry types benefit from this. * Use devirtualization for the offset and position input. This optimizes the common case that they are either single values or computed in the fly in a span. * Write to `Mesh->mvert` directly instead of creating a temporary span. This makes setting mesh vertex positions even more efficient. In my simple benchmark I'm using a White Noise node to offset the position of 1,000,000 vertices. The speed is `20 ms -> 4.5 ms` in the multi-threaded case and `32 ms -> 22 ms` in the single-threaded case. --- source/blender/blenlib/BLI_virtual_array.hh | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'source/blender/blenlib') diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 2038abc0b77..85e9cb25b3f 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -183,6 +183,15 @@ template class VArrayImpl { * own anything can overwrite this with false. */ return true; } + + /** + * Return true when the other virtual array should be considered to be the same, e.g. because it + * shares the same underlying memory. + */ + virtual bool is_same(const VArrayImpl &UNUSED(other)) const + { + return false; + } }; /* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */ @@ -260,6 +269,18 @@ template class VArrayImpl_For_Span : public VMutableArrayImpl { { return Span(data_, this->size_); } + + bool is_same(const VArrayImpl &other) const final + { + if (other.size() != this->size_) { + return false; + } + if (!other.is_span()) { + return false; + } + const Span other_span = other.get_internal_span(); + return data_ == other_span.data(); + } }; /** @@ -388,6 +409,12 @@ class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl { { } + template + friend class VArrayImpl_For_DerivedSpan; + private: ElemT get(const int64_t index) const override { @@ -416,6 +443,23 @@ class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl { { return false; } + + bool is_same(const VArrayImpl &other) const override + { + if (other.size() != this->size_) { + return false; + } + if (const VArrayImpl_For_DerivedSpan *other_typed = + dynamic_cast *>(&other)) { + return other_typed->data_ == data_; + } + if (const VArrayImpl_For_DerivedSpan *other_typed = + dynamic_cast *>( + &other)) { + return other_typed->data_ == data_; + } + return false; + } }; namespace detail { @@ -670,6 +714,25 @@ template class VArrayCommon { return impl_->get_internal_single(); } + /** + * Return true when the other virtual references the same underlying memory. + */ + bool is_same(const VArrayCommon &other) const + { + if (!*this || !other) { + return false; + } + /* Check in both directions in case one does not know how to compare to the other + * implementation. */ + if (impl_->is_same(*other.impl_)) { + return true; + } + if (other.impl_->is_same(*impl_)) { + return true; + } + return false; + } + /** Copy the entire virtual array into a span. */ void materialize(MutableSpan r_span) const { -- cgit v1.2.3