diff options
author | Jacques Lucke <jacques@blender.org> | 2021-11-23 16:47:25 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-11-23 16:49:26 +0300 |
commit | 47276b84701727c2f187c77f1ec502b4ca4963bd (patch) | |
tree | ac6e6fced7908dbaa984cfe686b2e3a080b99fc7 /source/blender/functions/FN_field_cpp_type.hh | |
parent | 0bedd5d14f6d61a6a4a96cc7f88484b0dc46f752 (diff) |
Geometry Nodes: reduce overhead when processing single values
Currently the geometry nodes evaluator always stores a field for every
type that supports it, even if it is just a single value. This results in a lot
of overhead when there are many sockets that just contain a single
value, which is often the case.
This introduces a new `ValueOrField<T>` type that is used by the geometry
nodes evaluator. Now a field will only be created when it is actually
necessary. See D13307 for more details. In extrem cases this can speed
up the evaluation 2-3x (those cases are probably never hit in practice
though, but it's good to get rid of unnecessary overhead nevertheless).
Differential Revision: https://developer.blender.org/D13307
Diffstat (limited to 'source/blender/functions/FN_field_cpp_type.hh')
-rw-r--r-- | source/blender/functions/FN_field_cpp_type.hh | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh index c3636fb3c7b..940faba6d70 100644 --- a/source/blender/functions/FN_field_cpp_type.hh +++ b/source/blender/functions/FN_field_cpp_type.hh @@ -60,6 +60,84 @@ class FieldCPPType : public CPPType { } }; +class ValueOrFieldCPPType : public CPPType { + private: + const CPPType &base_type_; + void (*construct_from_value_)(void *dst, const void *value); + void (*construct_from_field_)(void *dst, GField field); + const void *(*get_value_ptr_)(const void *value_or_field); + const GField *(*get_field_ptr_)(const void *value_or_field); + bool (*is_field_)(const void *value_or_field); + GField (*as_field_)(const void *value_or_field); + + public: + template<typename T> + ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name) + : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name), + base_type_(CPPType::get<T>()) + { + construct_from_value_ = [](void *dst, const void *value_or_field) { + new (dst) ValueOrField<T>(*(const T *)value_or_field); + }; + construct_from_field_ = [](void *dst, GField field) { + new (dst) ValueOrField<T>(Field<T>(std::move(field))); + }; + get_value_ptr_ = [](const void *value_or_field) { + return (const void *)&((ValueOrField<T> *)value_or_field)->value; + }; + get_field_ptr_ = [](const void *value_or_field) -> const GField * { + return &((ValueOrField<T> *)value_or_field)->field; + }; + is_field_ = [](const void *value_or_field) { + return ((ValueOrField<T> *)value_or_field)->is_field(); + }; + as_field_ = [](const void *value_or_field) -> GField { + return ((ValueOrField<T> *)value_or_field)->as_field(); + }; + } + + const CPPType &base_type() const + { + return base_type_; + } + + void construct_from_value(void *dst, const void *value) const + { + construct_from_value_(dst, value); + } + + void construct_from_field(void *dst, GField field) const + { + construct_from_field_(dst, field); + } + + const void *get_value_ptr(const void *value_or_field) const + { + return get_value_ptr_(value_or_field); + } + + void *get_value_ptr(void *value_or_field) const + { + /* Use `const_cast` to avoid duplicating the callback for the non-const case. */ + return const_cast<void *>(get_value_ptr_(value_or_field)); + } + + const GField *get_field_ptr(const void *value_or_field) const + { + return get_field_ptr_(value_or_field); + } + + bool is_field(const void *value_or_field) const + { + return is_field_(value_or_field); + } + + GField as_field(const void *value_or_field) const + { + return as_field_(value_or_field); + } +}; + } // namespace blender::fn #define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \ @@ -69,4 +147,13 @@ class FieldCPPType : public CPPType { static blender::fn::FieldCPPType cpp_type{ \ blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \ return cpp_type; \ + } \ + template<> \ + const blender::fn::CPPType & \ + blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \ + { \ + static blender::fn::ValueOrFieldCPPType cpp_type{ \ + blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \ + STRINGIFY(DEBUG_NAME##OrValue)}; \ + return cpp_type; \ } |