Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/intern/geometry_nodes_lazy_function.cc
| Show All 10 Lines | |||||
| * complexity. So far, this does not seem to be a performance issue. | * complexity. So far, this does not seem to be a performance issue. | ||||
| */ | */ | ||||
| #include "NOD_geometry_exec.hh" | #include "NOD_geometry_exec.hh" | ||||
| #include "NOD_geometry_nodes_lazy_function.hh" | #include "NOD_geometry_nodes_lazy_function.hh" | ||||
| #include "NOD_multi_function.hh" | #include "NOD_multi_function.hh" | ||||
| #include "NOD_node_declaration.hh" | #include "NOD_node_declaration.hh" | ||||
| #include "BLI_cpp_types.hh" | |||||
| #include "BLI_lazy_threading.hh" | #include "BLI_lazy_threading.hh" | ||||
| #include "BLI_map.hh" | #include "BLI_map.hh" | ||||
| #include "DNA_ID.h" | #include "DNA_ID.h" | ||||
| #include "BKE_compute_contexts.hh" | #include "BKE_compute_contexts.hh" | ||||
| #include "BKE_geometry_set.hh" | #include "BKE_geometry_set.hh" | ||||
| #include "BKE_type_conversions.hh" | #include "BKE_type_conversions.hh" | ||||
| Show All 21 Lines | |||||
| static const CPPType *get_socket_cpp_type(const bNodeSocket &socket) | static const CPPType *get_socket_cpp_type(const bNodeSocket &socket) | ||||
| { | { | ||||
| return get_socket_cpp_type(*socket.typeinfo); | return get_socket_cpp_type(*socket.typeinfo); | ||||
| } | } | ||||
| static const CPPType *get_vector_type(const CPPType &type) | static const CPPType *get_vector_type(const CPPType &type) | ||||
| { | { | ||||
| /* This could be generalized in the future. For now we only support a small set of vectors. */ | const VectorCPPType *vector_type = VectorCPPType::get_from_value(type); | ||||
| if (type.is<GeometrySet>()) { | if (vector_type == nullptr) { | ||||
| return &CPPType::get<Vector<GeometrySet>>(); | |||||
| } | |||||
| if (type.is<ValueOrField<std::string>>()) { | |||||
| return &CPPType::get<Vector<ValueOrField<std::string>>>(); | |||||
| } | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| return &vector_type->self; | |||||
| } | |||||
| /** | /** | ||||
| * Checks which sockets of the node are available and creates corresponding inputs/outputs on the | * Checks which sockets of the node are available and creates corresponding inputs/outputs on the | ||||
| * lazy-function. | * lazy-function. | ||||
| */ | */ | ||||
| static void lazy_function_interface_from_node(const bNode &node, | static void lazy_function_interface_from_node(const bNode &node, | ||||
| Vector<const bNodeSocket *> &r_used_inputs, | Vector<const bNodeSocket *> &r_used_inputs, | ||||
| Vector<const bNodeSocket *> &r_used_outputs, | Vector<const bNodeSocket *> &r_used_outputs, | ||||
| ▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | static void execute_multi_function_on_value_or_field( | ||||
| } | } | ||||
| else { | else { | ||||
| /* In this case, the multi-function is evaluated directly. */ | /* In this case, the multi-function is evaluated directly. */ | ||||
| MFParamsBuilder params{fn, 1}; | MFParamsBuilder params{fn, 1}; | ||||
| MFContextBuilder context; | MFContextBuilder context; | ||||
| for (const int i : input_types.index_range()) { | for (const int i : input_types.index_range()) { | ||||
| const ValueOrFieldCPPType &type = *input_types[i]; | const ValueOrFieldCPPType &type = *input_types[i]; | ||||
| const CPPType &base_type = type.base_type(); | |||||
| const void *value_or_field = input_values[i]; | const void *value_or_field = input_values[i]; | ||||
| const void *value = type.get_value_ptr(value_or_field); | const void *value = type.get_value_ptr(value_or_field); | ||||
| params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, value)); | params.add_readonly_single_input(GVArray::ForSingleRef(type.value, 1, value)); | ||||
| } | } | ||||
| for (const int i : output_types.index_range()) { | for (const int i : output_types.index_range()) { | ||||
| const ValueOrFieldCPPType &type = *output_types[i]; | const ValueOrFieldCPPType &type = *output_types[i]; | ||||
| const CPPType &base_type = type.base_type(); | |||||
| void *value_or_field = output_values[i]; | void *value_or_field = output_values[i]; | ||||
| type.default_construct(value_or_field); | type.self.default_construct(value_or_field); | ||||
| void *value = type.get_value_ptr(value_or_field); | void *value = type.get_value_ptr(value_or_field); | ||||
| base_type.destruct(value); | type.value.destruct(value); | ||||
| params.add_uninitialized_single_output(GMutableSpan{base_type, value, 1}); | params.add_uninitialized_single_output(GMutableSpan{type.value, value, 1}); | ||||
| } | } | ||||
| fn.call(IndexRange(1), params, context); | fn.call(IndexRange(1), params, context); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Behavior of muted nodes: | * Behavior of muted nodes: | ||||
| * - Some inputs are forwarded to outputs without changes. | * - Some inputs are forwarded to outputs without changes. | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | for (const int output_i : outputs_.index_range()) { | ||||
| if (input_type == output_type) { | if (input_type == output_type) { | ||||
| /* Forward the value as is. */ | /* Forward the value as is. */ | ||||
| input_type.copy_construct(input_value, output_value); | input_type.copy_construct(input_value, output_value); | ||||
| params.output_set(output_i); | params.output_set(output_i); | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Perform a type conversion and then format the value. */ | /* Perform a type conversion and then format the value. */ | ||||
| const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); | const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); | ||||
| const auto *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&input_type); | const auto *from_type = ValueOrFieldCPPType::get_from_self(input_type); | ||||
| const auto *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&output_type); | const auto *to_type = ValueOrFieldCPPType::get_from_self(output_type); | ||||
| if (from_field_type != nullptr && to_field_type != nullptr) { | if (from_type != nullptr && to_type != nullptr) { | ||||
| const CPPType &from_base_type = from_field_type->base_type(); | if (conversions.is_convertible(from_type->value, to_type->value)) { | ||||
| const CPPType &to_base_type = to_field_type->base_type(); | |||||
| if (conversions.is_convertible(from_base_type, to_base_type)) { | |||||
| const MultiFunction &multi_fn = *conversions.get_conversion_multi_function( | const MultiFunction &multi_fn = *conversions.get_conversion_multi_function( | ||||
| MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); | MFDataType::ForSingle(from_type->value), MFDataType::ForSingle(to_type->value)); | ||||
| execute_multi_function_on_value_or_field( | execute_multi_function_on_value_or_field( | ||||
| multi_fn, {}, {from_field_type}, {to_field_type}, {input_value}, {output_value}); | multi_fn, {}, {from_type}, {to_type}, {input_value}, {output_value}); | ||||
| } | } | ||||
| params.output_set(output_i); | params.output_set(output_i); | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Use a value initialization if the conversion does not work. */ | /* Use a value initialization if the conversion does not work. */ | ||||
| output_type.value_initialize(output_value); | output_type.value_initialize(output_value); | ||||
| params.output_set(output_i); | params.output_set(output_i); | ||||
| } | } | ||||
| Show All 14 Lines | |||||
| public: | public: | ||||
| LazyFunctionForMultiFunctionConversion(const MultiFunction &fn, | LazyFunctionForMultiFunctionConversion(const MultiFunction &fn, | ||||
| const ValueOrFieldCPPType &from, | const ValueOrFieldCPPType &from, | ||||
| const ValueOrFieldCPPType &to, | const ValueOrFieldCPPType &to, | ||||
| Vector<const bNodeSocket *> &&target_sockets) | Vector<const bNodeSocket *> &&target_sockets) | ||||
| : fn_(fn), from_type_(from), to_type_(to), target_sockets_(std::move(target_sockets)) | : fn_(fn), from_type_(from), to_type_(to), target_sockets_(std::move(target_sockets)) | ||||
| { | { | ||||
| debug_name_ = "Convert"; | debug_name_ = "Convert"; | ||||
| inputs_.append({"From", from}); | inputs_.append({"From", from.self}); | ||||
| outputs_.append({"To", to}); | outputs_.append({"To", to.self}); | ||||
| } | } | ||||
| void execute_impl(lf::Params ¶ms, const lf::Context & /*context*/) const override | void execute_impl(lf::Params ¶ms, const lf::Context & /*context*/) const override | ||||
| { | { | ||||
| const void *from_value = params.try_get_input_data_ptr(0); | const void *from_value = params.try_get_input_data_ptr(0); | ||||
| void *to_value = params.get_output_data_ptr(0); | void *to_value = params.get_output_data_ptr(0); | ||||
| BLI_assert(from_value != nullptr); | BLI_assert(from_value != nullptr); | ||||
| BLI_assert(to_value != nullptr); | BLI_assert(to_value != nullptr); | ||||
| Show All 20 Lines | LazyFunctionForMultiFunctionNode(const bNode &node, | ||||
| Vector<const bNodeSocket *> &r_used_inputs, | Vector<const bNodeSocket *> &r_used_inputs, | ||||
| Vector<const bNodeSocket *> &r_used_outputs) | Vector<const bNodeSocket *> &r_used_outputs) | ||||
| : fn_item_(std::move(fn_item)) | : fn_item_(std::move(fn_item)) | ||||
| { | { | ||||
| BLI_assert(fn_item_.fn != nullptr); | BLI_assert(fn_item_.fn != nullptr); | ||||
| debug_name_ = node.name; | debug_name_ = node.name; | ||||
| lazy_function_interface_from_node(node, r_used_inputs, r_used_outputs, inputs_, outputs_); | lazy_function_interface_from_node(node, r_used_inputs, r_used_outputs, inputs_, outputs_); | ||||
| for (const lf::Input &fn_input : inputs_) { | for (const lf::Input &fn_input : inputs_) { | ||||
| input_types_.append(dynamic_cast<const ValueOrFieldCPPType *>(fn_input.type)); | input_types_.append(ValueOrFieldCPPType::get_from_self(*fn_input.type)); | ||||
| } | } | ||||
| for (const lf::Output &fn_output : outputs_) { | for (const lf::Output &fn_output : outputs_) { | ||||
| output_types_.append(dynamic_cast<const ValueOrFieldCPPType *>(fn_output.type)); | output_types_.append(ValueOrFieldCPPType::get_from_self(*fn_output.type)); | ||||
| } | } | ||||
| } | } | ||||
| void execute_impl(lf::Params ¶ms, const lf::Context & /*context*/) const override | void execute_impl(lf::Params ¶ms, const lf::Context & /*context*/) const override | ||||
| { | { | ||||
| Vector<const void *> input_values(inputs_.size()); | Vector<const void *> input_values(inputs_.size()); | ||||
| Vector<void *> output_values(outputs_.size()); | Vector<void *> output_values(outputs_.size()); | ||||
| for (const int i : inputs_.index_range()) { | for (const int i : inputs_.index_range()) { | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| public: | public: | ||||
| LazyFunctionForViewerNode(const bNode &bnode, Vector<const bNodeSocket *> &r_used_inputs) | LazyFunctionForViewerNode(const bNode &bnode, Vector<const bNodeSocket *> &r_used_inputs) | ||||
| : bnode_(bnode) | : bnode_(bnode) | ||||
| { | { | ||||
| debug_name_ = "Viewer"; | debug_name_ = "Viewer"; | ||||
| Vector<const bNodeSocket *> dummy_used_outputs; | Vector<const bNodeSocket *> dummy_used_outputs; | ||||
| lazy_function_interface_from_node(bnode, r_used_inputs, dummy_used_outputs, inputs_, outputs_); | lazy_function_interface_from_node(bnode, r_used_inputs, dummy_used_outputs, inputs_, outputs_); | ||||
| if (!r_used_inputs[1]->is_directly_linked()) { | const Span<const bNodeLink *> links = r_used_inputs[1]->directly_linked_links(); | ||||
| if (links.is_empty() || nodeIsDanglingReroute(&bnode.owner_tree(), links.first()->fromnode)) { | |||||
| use_field_input_ = false; | use_field_input_ = false; | ||||
| r_used_inputs.pop_last(); | r_used_inputs.pop_last(); | ||||
| inputs_.pop_last(); | inputs_.pop_last(); | ||||
| } | } | ||||
| } | } | ||||
| void execute_impl(lf::Params ¶ms, const lf::Context &context) const override | void execute_impl(lf::Params ¶ms, const lf::Context &context) const override | ||||
| { | { | ||||
| GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data); | GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data); | ||||
| BLI_assert(user_data != nullptr); | BLI_assert(user_data != nullptr); | ||||
| if (user_data->modifier_data == nullptr) { | if (user_data->modifier_data == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (user_data->modifier_data->eval_log == nullptr) { | if (user_data->modifier_data->eval_log == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| GeometrySet geometry = params.extract_input<GeometrySet>(0); | GeometrySet geometry = params.extract_input<GeometrySet>(0); | ||||
| const NodeGeometryViewer *storage = static_cast<NodeGeometryViewer *>(bnode_.storage); | const NodeGeometryViewer *storage = static_cast<NodeGeometryViewer *>(bnode_.storage); | ||||
| if (use_field_input_) { | if (use_field_input_) { | ||||
| const void *value_or_field = params.try_get_input_data_ptr(1); | const void *value_or_field = params.try_get_input_data_ptr(1); | ||||
| BLI_assert(value_or_field != nullptr); | BLI_assert(value_or_field != nullptr); | ||||
| const ValueOrFieldCPPType &value_or_field_type = static_cast<const ValueOrFieldCPPType &>( | const auto &value_or_field_type = *ValueOrFieldCPPType::get_from_self(*inputs_[1].type); | ||||
| *inputs_[1].type); | |||||
| GField field = value_or_field_type.as_field(value_or_field); | GField field = value_or_field_type.as_field(value_or_field); | ||||
| const eAttrDomain domain = eAttrDomain(storage->domain); | const eAttrDomain domain = eAttrDomain(storage->domain); | ||||
| const StringRefNull viewer_attribute_name = ".viewer"; | const StringRefNull viewer_attribute_name = ".viewer"; | ||||
| if (domain == ATTR_DOMAIN_INSTANCE) { | if (domain == ATTR_DOMAIN_INSTANCE) { | ||||
| if (geometry.has_instances()) { | if (geometry.has_instances()) { | ||||
| GeometryComponent &component = geometry.get_component_for_write( | GeometryComponent &component = geometry.get_component_for_write( | ||||
| GEO_COMPONENT_TYPE_INSTANCES); | GEO_COMPONENT_TYPE_INSTANCES); | ||||
| bke::try_capture_field_on_geometry( | bke::try_capture_field_on_geometry( | ||||
| ▲ Show 20 Lines • Show All 623 Lines • ▼ Show 20 Lines | lf::OutputSocket *insert_type_conversion_if_necessary( | ||||
| lf::OutputSocket &from_socket, | lf::OutputSocket &from_socket, | ||||
| const CPPType &to_type, | const CPPType &to_type, | ||||
| Vector<const bNodeSocket *> &&target_sockets) | Vector<const bNodeSocket *> &&target_sockets) | ||||
| { | { | ||||
| const CPPType &from_type = from_socket.type(); | const CPPType &from_type = from_socket.type(); | ||||
| if (from_type == to_type) { | if (from_type == to_type) { | ||||
| return &from_socket; | return &from_socket; | ||||
| } | } | ||||
| const auto *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&from_type); | const auto *from_field_type = ValueOrFieldCPPType::get_from_self(from_type); | ||||
| const auto *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type); | const auto *to_field_type = ValueOrFieldCPPType::get_from_self(to_type); | ||||
| if (from_field_type != nullptr && to_field_type != nullptr) { | if (from_field_type != nullptr && to_field_type != nullptr) { | ||||
| const CPPType &from_base_type = from_field_type->base_type(); | if (conversions_->is_convertible(from_field_type->value, to_field_type->value)) { | ||||
| const CPPType &to_base_type = to_field_type->base_type(); | |||||
| if (conversions_->is_convertible(from_base_type, to_base_type)) { | |||||
| const MultiFunction &multi_fn = *conversions_->get_conversion_multi_function( | const MultiFunction &multi_fn = *conversions_->get_conversion_multi_function( | ||||
| MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); | MFDataType::ForSingle(from_field_type->value), | ||||
| MFDataType::ForSingle(to_field_type->value)); | |||||
| auto fn = std::make_unique<LazyFunctionForMultiFunctionConversion>( | auto fn = std::make_unique<LazyFunctionForMultiFunctionConversion>( | ||||
| multi_fn, *from_field_type, *to_field_type, std::move(target_sockets)); | multi_fn, *from_field_type, *to_field_type, std::move(target_sockets)); | ||||
| lf::Node &conversion_node = lf_graph_->add_function(*fn); | lf::Node &conversion_node = lf_graph_->add_function(*fn); | ||||
| lf_graph_info_->functions.append(std::move(fn)); | lf_graph_info_->functions.append(std::move(fn)); | ||||
| lf_graph_->add_link(from_socket, conversion_node.input(0)); | lf_graph_->add_link(from_socket, conversion_node.input(0)); | ||||
| return &conversion_node.output(0); | return &conversion_node.output(0); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 232 Lines • Show Last 20 Lines | |||||