From 05dbbd83f00d270c00cb1a0904c504c31e1812af Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 15 Apr 2021 11:21:35 +0200 Subject: Geometry Nodes: refactor implicit conversions This refactor simplifies having standalone function pointer that does a single conversion. It also speeds up implicit type conversion of attributes. --- .../blender/blenkernel/intern/attribute_access.cc | 12 +- source/blender/modifiers/intern/MOD_nodes.cc | 5 +- source/blender/nodes/NOD_type_conversions.hh | 43 +++- .../nodes/intern/node_tree_multi_function.cc | 4 +- source/blender/nodes/intern/type_conversions.cc | 263 ++++++++++++++------- 5 files changed, 230 insertions(+), 97 deletions(-) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 8542c9d35a4..ac582fc30e7 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -210,23 +210,25 @@ class ConvertedReadAttribute final : public ReadAttribute { const CPPType &from_type_; const CPPType &to_type_; ReadAttributePtr base_attribute_; - const nodes::DataTypeConversions &conversions_; + void (*convert_)(const void *src, void *dst); public: ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type) : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()), from_type_(base_attribute->cpp_type()), to_type_(to_type), - base_attribute_(std::move(base_attribute)), - conversions_(nodes::get_implicit_type_conversions()) + base_attribute_(std::move(base_attribute)) { + const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions(); + convert_ = conversions.get_conversion_functions(base_attribute_->cpp_type(), to_type) + ->convert_single_to_uninitialized; } void get_internal(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); base_attribute_->get(index, buffer); - conversions_.convert(from_type_, to_type_, buffer, r_value); + convert_(buffer, r_value); } }; @@ -989,7 +991,7 @@ blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_rea BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type)); void *out_value = alloca(out_cpp_type->size()); - conversions.convert(*in_cpp_type, *out_cpp_type, value, out_value); + conversions.convert_to_uninitialized(*in_cpp_type, *out_cpp_type, value, out_value); const int domain_size = this->attribute_domain_size(domain); blender::bke::ReadAttributePtr attribute = std::make_unique( diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 9329bc85e66..4a384063571 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -583,7 +583,8 @@ class GeometryNodesEvaluator { else { void *buffer = allocator_.allocate(to_type.size(), to_type.alignment()); if (conversions_.is_convertible(from_type, to_type)) { - conversions_.convert(from_type, to_type, value_to_forward.get(), buffer); + conversions_.convert_to_uninitialized( + from_type, to_type, value_to_forward.get(), buffer); } else { to_type.copy_to_uninitialized(to_type.default_value(), buffer); @@ -653,7 +654,7 @@ class GeometryNodesEvaluator { if (conversions_.is_convertible(type, required_type)) { void *converted_buffer = allocator_.allocate(required_type.size(), required_type.alignment()); - conversions_.convert(type, required_type, buffer, converted_buffer); + conversions_.convert_to_uninitialized(type, required_type, buffer, converted_buffer); type.destruct(buffer); return {required_type, converted_buffer}; } diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh index e23fddab58b..34225208fe6 100644 --- a/source/blender/nodes/NOD_type_conversions.hh +++ b/source/blender/nodes/NOD_type_conversions.hh @@ -21,20 +21,45 @@ namespace blender::nodes { using fn::CPPType; +using fn::GVArray; + +struct ConversionFunctions { + const fn::MultiFunction *multi_function; + void (*convert_single_to_initialized)(const void *src, void *dst); + void (*convert_single_to_uninitialized)(const void *src, void *dst); +}; class DataTypeConversions { private: - Map, const fn::MultiFunction *> conversions_; + Map, ConversionFunctions> conversions_; public: - void add(fn::MFDataType from_type, fn::MFDataType to_type, const fn::MultiFunction &fn) + void add(fn::MFDataType from_type, + fn::MFDataType to_type, + const fn::MultiFunction &fn, + void (*convert_single_to_initialized)(const void *src, void *dst), + void (*convert_single_to_uninitialized)(const void *src, void *dst)) + { + conversions_.add_new({from_type, to_type}, + {&fn, convert_single_to_initialized, convert_single_to_uninitialized}); + } + + const ConversionFunctions *get_conversion_functions(fn::MFDataType from, fn::MFDataType to) const + { + return conversions_.lookup_ptr({from, to}); + } + + const ConversionFunctions *get_conversion_functions(const CPPType &from, const CPPType &to) const { - conversions_.add_new({from_type, to_type}, &fn); + return this->get_conversion_functions(fn::MFDataType::ForSingle(from), + fn::MFDataType::ForSingle(to)); } - const fn::MultiFunction *get_conversion(fn::MFDataType from, fn::MFDataType to) const + const fn::MultiFunction *get_conversion_multi_function(fn::MFDataType from, + fn::MFDataType to) const { - return conversions_.lookup_default({from, to}, nullptr); + const ConversionFunctions *functions = this->get_conversion_functions(from, to); + return functions ? functions->multi_function : nullptr; } bool is_convertible(const CPPType &from_type, const CPPType &to_type) const @@ -43,10 +68,10 @@ class DataTypeConversions { {fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)}); } - void convert(const CPPType &from_type, - const CPPType &to_type, - const void *from_value, - void *to_value) const; + void convert_to_uninitialized(const CPPType &from_type, + const CPPType &to_type, + const void *from_value, + void *to_value) const; }; const DataTypeConversions &get_implicit_type_conversions(); diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index ea6b2e870ca..7ab6495f733 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -219,8 +219,8 @@ static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) const fn::MFDataType from_type = from_socket->data_type(); if (from_type != to_type) { - const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( - from_type, to_type); + const fn::MultiFunction *conversion_fn = + get_implicit_type_conversions().get_conversion_multi_function(from_type, to_type); if (conversion_fn != nullptr) { fn::MFNode &node = common.network.add_function(*conversion_fn); common.network.add_link(*from_socket, node.input(0)); diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc index 0f6bfa1d6d1..1c1b7c7feb5 100644 --- a/source/blender/nodes/intern/type_conversions.cc +++ b/source/blender/nodes/intern/type_conversions.cc @@ -26,83 +26,192 @@ namespace blender::nodes { using fn::MFDataType; -template +template static void add_implicit_conversion(DataTypeConversions &conversions) { - static fn::CustomMF_Convert function; - conversions.add(fn::MFDataType::ForSingle(), fn::MFDataType::ForSingle(), function); + const CPPType &from_type = CPPType::get(); + const CPPType &to_type = CPPType::get(); + const std::string conversion_name = from_type.name() + " to " + to_type.name(); + + static fn::CustomMF_SI_SO multi_function{conversion_name, ConversionF}; + static auto convert_single_to_initialized = [](const void *src, void *dst) { + *(To *)dst = ConversionF(*(const From *)src); + }; + static auto convert_single_to_uninitialized = [](const void *src, void *dst) { + new (dst) To(ConversionF(*(const From *)src)); + }; + conversions.add(fn::MFDataType::ForSingle(), + fn::MFDataType::ForSingle(), + multi_function, + convert_single_to_initialized, + convert_single_to_uninitialized); } -template -static void add_implicit_conversion(DataTypeConversions &conversions, - StringRef name, - ConversionF conversion) +static float2 float_to_float2(const float &a) { - static fn::CustomMF_SI_SO function{name, conversion}; - conversions.add(fn::MFDataType::ForSingle(), fn::MFDataType::ForSingle(), function); + return float2(a); +} +static float3 float_to_float3(const float &a) +{ + return float3(a); +} +static int32_t float_to_int(const float &a) +{ + return (int32_t)a; +} +static bool float_to_bool(const float &a) +{ + return a > 0.0f; +} +static Color4f float_to_color(const float &a) +{ + return Color4f(a, a, a, 1.0f); +} + +static float3 float2_to_float3(const float2 &a) +{ + return float3(a.x, a.y, 0.0f); +} +static float float2_to_float(const float2 &a) +{ + return (a.x + a.y) / 2.0f; +} +static int float2_to_int(const float2 &a) +{ + return (int32_t)((a.x + a.y) / 2.0f); +} +static bool float2_to_bool(const float2 &a) +{ + return !is_zero_v2(a); +} +static Color4f float2_to_color(const float2 &a) +{ + return Color4f(a.x, a.y, 0.0f, 1.0f); +} + +static bool float3_to_bool(const float3 &a) +{ + return !is_zero_v3(a); +} +static float float3_to_float(const float3 &a) +{ + return (a.x + a.y + a.z) / 3.0f; +} +static int float3_to_int(const float3 &a) +{ + return (int)((a.x + a.y + a.z) / 3.0f); +} +static float2 float3_to_float2(const float3 &a) +{ + return float2(a); +} +static Color4f float3_to_color(const float3 &a) +{ + return Color4f(a.x, a.y, a.z, 1.0f); +} + +static bool int_to_bool(const int32_t &a) +{ + return a > 0; +} +static float int_to_float(const int32_t &a) +{ + return (float)a; +} +static float2 int_to_float2(const int32_t &a) +{ + return float2((float)a); +} +static float3 int_to_float3(const int32_t &a) +{ + return float3((float)a); +} +static Color4f int_to_color(const int32_t &a) +{ + return Color4f((float)a, (float)a, (float)a, 1.0f); +} + +static float bool_to_float(const bool &a) +{ + return (bool)a; +} +static int32_t bool_to_int(const bool &a) +{ + return (int32_t)a; +} +static float2 bool_to_float2(const bool &a) +{ + return (a) ? float2(1.0f) : float2(0.0f); +} +static float3 bool_to_float3(const bool &a) +{ + return (a) ? float3(1.0f) : float3(0.0f); +} +static Color4f bool_to_color(const bool &a) +{ + return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f); +} + +static bool color_to_bool(const Color4f &a) +{ + return rgb_to_grayscale(a) > 0.0f; +} +static float color_to_float(const Color4f &a) +{ + return rgb_to_grayscale(a); +} +static int32_t color_to_int(const Color4f &a) +{ + return (int)rgb_to_grayscale(a); +} +static float2 color_to_float2(const Color4f &a) +{ + return float2(a.r, a.g); +} +static float3 color_to_float3(const Color4f &a) +{ + return float3(a.r, a.g, a.b); } static DataTypeConversions create_implicit_conversions() { DataTypeConversions conversions; - add_implicit_conversion(conversions); - add_implicit_conversion(conversions); - add_implicit_conversion(conversions); - add_implicit_conversion( - conversions, "float to boolean", [](float a) { return a > 0.0f; }); - add_implicit_conversion( - conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); - - add_implicit_conversion( - conversions, "float2 to float3", [](float2 a) { return float3(a.x, a.y, 0.0f); }); - add_implicit_conversion( - conversions, "float2 to float", [](float2 a) { return (a.x + a.y) / 2.0f; }); - add_implicit_conversion( - conversions, "float2 to int32_t", [](float2 a) { return (int32_t)((a.x + a.y) / 2.0f); }); - add_implicit_conversion( - conversions, "float2 to bool", [](float2 a) { return !is_zero_v2(a); }); - add_implicit_conversion( - conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); }); - - add_implicit_conversion( - conversions, "float3 to boolean", [](float3 a) { return !is_zero_v3(a); }); - add_implicit_conversion( - conversions, "float3 to float", [](float3 a) { return (a.x + a.y + a.z) / 3.0f; }); - add_implicit_conversion( - conversions, "float3 to int32_t", [](float3 a) { return (int)((a.x + a.y + a.z) / 3.0f); }); - add_implicit_conversion(conversions); - add_implicit_conversion( - conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); }); - - add_implicit_conversion( - conversions, "int32 to boolean", [](int32_t a) { return a > 0; }); - add_implicit_conversion(conversions); - add_implicit_conversion( - conversions, "int32 to float2", [](int32_t a) { return float2((float)a); }); - add_implicit_conversion( - conversions, "int32 to float3", [](int32_t a) { return float3((float)a); }); - add_implicit_conversion(conversions, "int32 to Color4f", [](int32_t a) { - return Color4f((float)a, (float)a, (float)a, 1.0f); - }); - - add_implicit_conversion(conversions); - add_implicit_conversion(conversions); - add_implicit_conversion( - conversions, "boolean to float2", [](bool a) { return (a) ? float2(1.0f) : float2(0.0f); }); - add_implicit_conversion( - conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); }); - add_implicit_conversion(conversions, "boolean to Color4f", [](bool a) { - return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f); - }); - - add_implicit_conversion( - conversions, "Color4f to boolean", [](Color4f a) { return rgb_to_grayscale(a) > 0.0f; }); - add_implicit_conversion( - conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); - add_implicit_conversion( - conversions, "Color4f to float2", [](Color4f a) { return float2(a.r, a.g); }); - add_implicit_conversion( - conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); }); + + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); return conversions; } @@ -113,20 +222,16 @@ const DataTypeConversions &get_implicit_type_conversions() return conversions; } -void DataTypeConversions::convert(const CPPType &from_type, - const CPPType &to_type, - const void *from_value, - void *to_value) const +void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, + const CPPType &to_type, + const void *from_value, + void *to_value) const { - const fn::MultiFunction *fn = this->get_conversion(MFDataType::ForSingle(from_type), - MFDataType::ForSingle(to_type)); - BLI_assert(fn != nullptr); + const ConversionFunctions *functions = this->get_conversion_functions( + MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type)); + BLI_assert(functions != nullptr); - fn::MFContextBuilder context; - fn::MFParamsBuilder params{*fn, 1}; - params.add_readonly_single_input(fn::GSpan(from_type, from_value, 1)); - params.add_uninitialized_single_output(fn::GMutableSpan(to_type, to_value, 1)); - fn->call({0}, params, context); + functions->convert_single_to_uninitialized(from_value, to_value); } } // namespace blender::nodes -- cgit v1.2.3