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.
This commit is contained in:
parent
2c3a9caffe
commit
05dbbd83f0
|
@ -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<blender::bke::ConstantReadAttribute>(
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
|
|
@ -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<std::pair<fn::MFDataType, fn::MFDataType>, const fn::MultiFunction *> conversions_;
|
||||
Map<std::pair<fn::MFDataType, fn::MFDataType>, 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);
|
||||
conversions_.add_new({from_type, to_type},
|
||||
{&fn, convert_single_to_initialized, convert_single_to_uninitialized});
|
||||
}
|
||||
|
||||
const fn::MultiFunction *get_conversion(fn::MFDataType from, fn::MFDataType to) const
|
||||
const ConversionFunctions *get_conversion_functions(fn::MFDataType from, fn::MFDataType to) const
|
||||
{
|
||||
return conversions_.lookup_default({from, to}, nullptr);
|
||||
return conversions_.lookup_ptr({from, to});
|
||||
}
|
||||
|
||||
const ConversionFunctions *get_conversion_functions(const CPPType &from, const CPPType &to) const
|
||||
{
|
||||
return this->get_conversion_functions(fn::MFDataType::ForSingle(from),
|
||||
fn::MFDataType::ForSingle(to));
|
||||
}
|
||||
|
||||
const fn::MultiFunction *get_conversion_multi_function(fn::MFDataType from,
|
||||
fn::MFDataType to) const
|
||||
{
|
||||
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();
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -26,83 +26,192 @@ namespace blender::nodes {
|
|||
|
||||
using fn::MFDataType;
|
||||
|
||||
template<typename From, typename To>
|
||||
template<typename From, typename To, To (*ConversionF)(const From &)>
|
||||
static void add_implicit_conversion(DataTypeConversions &conversions)
|
||||
{
|
||||
static fn::CustomMF_Convert<From, To> function;
|
||||
conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
|
||||
const CPPType &from_type = CPPType::get<From>();
|
||||
const CPPType &to_type = CPPType::get<To>();
|
||||
const std::string conversion_name = from_type.name() + " to " + to_type.name();
|
||||
|
||||
static fn::CustomMF_SI_SO<From, To> 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<From>(),
|
||||
fn::MFDataType::ForSingle<To>(),
|
||||
multi_function,
|
||||
convert_single_to_initialized,
|
||||
convert_single_to_uninitialized);
|
||||
}
|
||||
|
||||
template<typename From, typename To, typename ConversionF>
|
||||
static void add_implicit_conversion(DataTypeConversions &conversions,
|
||||
StringRef name,
|
||||
ConversionF conversion)
|
||||
static float2 float_to_float2(const float &a)
|
||||
{
|
||||
static fn::CustomMF_SI_SO<From, To> function{name, conversion};
|
||||
conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), 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<float, float2>(conversions);
|
||||
add_implicit_conversion<float, float3>(conversions);
|
||||
add_implicit_conversion<float, int32_t>(conversions);
|
||||
add_implicit_conversion<float, bool>(
|
||||
conversions, "float to boolean", [](float a) { return a > 0.0f; });
|
||||
add_implicit_conversion<float, Color4f>(
|
||||
conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); });
|
||||
|
||||
add_implicit_conversion<float2, float3>(
|
||||
conversions, "float2 to float3", [](float2 a) { return float3(a.x, a.y, 0.0f); });
|
||||
add_implicit_conversion<float2, float>(
|
||||
conversions, "float2 to float", [](float2 a) { return (a.x + a.y) / 2.0f; });
|
||||
add_implicit_conversion<float2, int32_t>(
|
||||
conversions, "float2 to int32_t", [](float2 a) { return (int32_t)((a.x + a.y) / 2.0f); });
|
||||
add_implicit_conversion<float2, bool>(
|
||||
conversions, "float2 to bool", [](float2 a) { return !is_zero_v2(a); });
|
||||
add_implicit_conversion<float2, Color4f>(
|
||||
conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); });
|
||||
add_implicit_conversion<float, float2, float_to_float2>(conversions);
|
||||
add_implicit_conversion<float, float3, float_to_float3>(conversions);
|
||||
add_implicit_conversion<float, int32_t, float_to_int>(conversions);
|
||||
add_implicit_conversion<float, bool, float_to_bool>(conversions);
|
||||
add_implicit_conversion<float, Color4f, float_to_color>(conversions);
|
||||
|
||||
add_implicit_conversion<float3, bool>(
|
||||
conversions, "float3 to boolean", [](float3 a) { return !is_zero_v3(a); });
|
||||
add_implicit_conversion<float3, float>(
|
||||
conversions, "float3 to float", [](float3 a) { return (a.x + a.y + a.z) / 3.0f; });
|
||||
add_implicit_conversion<float3, int32_t>(
|
||||
conversions, "float3 to int32_t", [](float3 a) { return (int)((a.x + a.y + a.z) / 3.0f); });
|
||||
add_implicit_conversion<float3, float2>(conversions);
|
||||
add_implicit_conversion<float3, Color4f>(
|
||||
conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
|
||||
add_implicit_conversion<float2, float3, float2_to_float3>(conversions);
|
||||
add_implicit_conversion<float2, float, float2_to_float>(conversions);
|
||||
add_implicit_conversion<float2, int32_t, float2_to_int>(conversions);
|
||||
add_implicit_conversion<float2, bool, float2_to_bool>(conversions);
|
||||
add_implicit_conversion<float2, Color4f, float2_to_color>(conversions);
|
||||
|
||||
add_implicit_conversion<int32_t, bool>(
|
||||
conversions, "int32 to boolean", [](int32_t a) { return a > 0; });
|
||||
add_implicit_conversion<int32_t, float>(conversions);
|
||||
add_implicit_conversion<int32_t, float2>(
|
||||
conversions, "int32 to float2", [](int32_t a) { return float2((float)a); });
|
||||
add_implicit_conversion<int32_t, float3>(
|
||||
conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
|
||||
add_implicit_conversion<int32_t, Color4f>(conversions, "int32 to Color4f", [](int32_t a) {
|
||||
return Color4f((float)a, (float)a, (float)a, 1.0f);
|
||||
});
|
||||
add_implicit_conversion<float3, bool, float3_to_bool>(conversions);
|
||||
add_implicit_conversion<float3, float, float3_to_float>(conversions);
|
||||
add_implicit_conversion<float3, int32_t, float3_to_int>(conversions);
|
||||
add_implicit_conversion<float3, float2, float3_to_float2>(conversions);
|
||||
add_implicit_conversion<float3, Color4f, float3_to_color>(conversions);
|
||||
|
||||
add_implicit_conversion<bool, float>(conversions);
|
||||
add_implicit_conversion<bool, int32_t>(conversions);
|
||||
add_implicit_conversion<bool, float2>(
|
||||
conversions, "boolean to float2", [](bool a) { return (a) ? float2(1.0f) : float2(0.0f); });
|
||||
add_implicit_conversion<bool, float3>(
|
||||
conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); });
|
||||
add_implicit_conversion<bool, Color4f>(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<int32_t, bool, int_to_bool>(conversions);
|
||||
add_implicit_conversion<int32_t, float, int_to_float>(conversions);
|
||||
add_implicit_conversion<int32_t, float2, int_to_float2>(conversions);
|
||||
add_implicit_conversion<int32_t, float3, int_to_float3>(conversions);
|
||||
add_implicit_conversion<int32_t, Color4f, int_to_color>(conversions);
|
||||
|
||||
add_implicit_conversion<Color4f, bool>(
|
||||
conversions, "Color4f to boolean", [](Color4f a) { return rgb_to_grayscale(a) > 0.0f; });
|
||||
add_implicit_conversion<Color4f, float>(
|
||||
conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
|
||||
add_implicit_conversion<Color4f, float2>(
|
||||
conversions, "Color4f to float2", [](Color4f a) { return float2(a.r, a.g); });
|
||||
add_implicit_conversion<Color4f, float3>(
|
||||
conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); });
|
||||
add_implicit_conversion<bool, float, bool_to_float>(conversions);
|
||||
add_implicit_conversion<bool, int32_t, bool_to_int>(conversions);
|
||||
add_implicit_conversion<bool, float2, bool_to_float2>(conversions);
|
||||
add_implicit_conversion<bool, float3, bool_to_float3>(conversions);
|
||||
add_implicit_conversion<bool, Color4f, bool_to_color>(conversions);
|
||||
|
||||
add_implicit_conversion<Color4f, bool, color_to_bool>(conversions);
|
||||
add_implicit_conversion<Color4f, float, color_to_float>(conversions);
|
||||
add_implicit_conversion<Color4f, int32_t, color_to_int>(conversions);
|
||||
add_implicit_conversion<Color4f, float2, color_to_float2>(conversions);
|
||||
add_implicit_conversion<Color4f, float3, color_to_float3>(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
|
||||
|
|
Loading…
Reference in New Issue