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/nodes | |
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/nodes')
-rw-r--r-- | source/blender/nodes/NOD_geometry_exec.hh | 43 | ||||
-rw-r--r-- | source/blender/nodes/intern/geometry_nodes_eval_log.cc | 46 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket.cc | 28 |
3 files changed, 72 insertions, 45 deletions
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 700f32ee414..6b6e8a89240 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -59,6 +59,7 @@ using fn::GVArray; using fn::GVArray_GSpan; using fn::GVMutableArray; using fn::GVMutableArray_GSpan; +using fn::ValueOrField; using geometry_nodes_eval_log::NodeWarningType; /** @@ -129,7 +130,7 @@ class GeoNodeExecParams { } template<typename T> - static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> || + static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, bool> || std::is_same_v<T, ColorGeometry4f> || @@ -157,9 +158,15 @@ class GeoNodeExecParams { */ template<typename T> T extract_input(StringRef identifier) { - if constexpr (is_stored_as_field_v<T>) { - Field<T> field = this->extract_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>( + identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -186,9 +193,9 @@ class GeoNodeExecParams { Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier); Vector<T> values; for (GMutablePointer gvalue : gvalues) { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> field = gvalue.relocate_out<Field<T>>(); - values.append(fn::evaluate_constant_field(field)); + if constexpr (is_field_base_type_v<T>) { + const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>(); + values.append(value_or_field.as_value()); } else { values.append(gvalue.relocate_out<T>()); @@ -200,11 +207,16 @@ class GeoNodeExecParams { /** * Get the input value for the input socket with the given identifier. */ - template<typename T> const T get_input(StringRef identifier) const + template<typename T> T get_input(StringRef identifier) const { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> &field = this->get_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -226,9 +238,12 @@ class GeoNodeExecParams { template<typename T> void set_output(StringRef identifier, T &&value) { using StoredT = std::decay_t<T>; - if constexpr (is_stored_as_field_v<StoredT>) { - this->set_output<Field<StoredT>>(identifier, - fn::make_constant_field<StoredT>(std::forward<T>(value))); + if constexpr (is_field_base_type_v<StoredT>) { + this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value))); + } + else if constexpr (fn::is_field_v<StoredT>) { + using BaseType = typename StoredT::base_type; + this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value))); } else { const CPPType &type = CPPType::get<StoredT>(); diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index ddd3c991518..782ab43336c 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -31,6 +31,7 @@ using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; +using fn::ValueOrFieldCPPType; ModifierLog::ModifierLog(GeoLogger &logger) : input_geometry_log_(std::move(logger.input_geometry_log_)), @@ -417,25 +418,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value geometry_set, log_full_geometry); values_.append({copied_sockets, std::move(value_log)}); } - else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) { - GField field = field_type->get_gfield(value.get()); - bool log_full_field = false; - if (!field.node().depends_on_input()) { - /* Always log constant fields so that their value can be shown in socket inspection. - * In the future we can also evaluate the field here and only store the value. */ - log_full_field = true; - } - if (!log_full_field) { - for (const DSocket &socket : sockets) { - if (main_logger_->log_full_sockets_.contains(socket)) { - log_full_field = true; - break; + else if (const ValueOrFieldCPPType *value_or_field_type = + dynamic_cast<const ValueOrFieldCPPType *>(&type)) { + const void *value_or_field = value.get(); + if (value_or_field_type->is_field(value_or_field)) { + GField field = *value_or_field_type->get_field_ptr(value_or_field); + bool log_full_field = false; + if (!field.node().depends_on_input()) { + /* Always log constant fields so that their value can be shown in socket inspection. + * In the future we can also evaluate the field here and only store the value. */ + log_full_field = true; + } + if (!log_full_field) { + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_sockets_.contains(socket)) { + log_full_field = true; + break; + } } } + destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( + std::move(field), log_full_field); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + const CPPType &base_type = value_or_field_type->base_type(); + const void *value = value_or_field_type->get_value_ptr(value_or_field); + void *buffer = allocator_->allocate(base_type.size(), base_type.alignment()); + base_type.copy_construct(value, buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{base_type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); } - destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( - std::move(field), log_full_field); - values_.append({copied_sockets, std::move(value_log)}); } else { void *buffer = allocator_->allocate(type.size(), type.alignment()); diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 200e4120346..68e8f6421bd 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -51,6 +51,7 @@ #include "FN_field.hh" using namespace blender; +using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -701,11 +702,11 @@ static bNodeSocketType *make_socket_type_bool() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<bool>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); }; return socktype; } @@ -717,11 +718,11 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<float>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); }; return socktype; } @@ -733,11 +734,11 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<int>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); }; return socktype; } @@ -749,12 +750,11 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::float3>(value); }; return socktype; } @@ -767,12 +767,11 @@ static bNodeSocketType *make_socket_type_rgba() *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); + &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) - blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::ColorGeometry4f>(value); }; return socktype; } @@ -784,13 +783,12 @@ static bNodeSocketType *make_socket_type_string() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<std::string>(value); }; return socktype; } |