diff options
-rw-r--r-- | source/blender/modifiers/intern/MOD_nodes_evaluator.cc | 111 | ||||
-rw-r--r-- | source/blender/nodes/NOD_derived_node_tree.hh | 15 | ||||
-rw-r--r-- | source/blender/nodes/intern/derived_node_tree.cc | 95 |
3 files changed, 137 insertions, 84 deletions
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index a312872f5d9..70d2bd9c7f5 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -568,15 +568,15 @@ class GeometryNodesEvaluator { } /* Count the number of potential users for this socket. */ socket.foreach_target_socket( - [&, this](const DInputSocket target_socket) { + [&, this](const DInputSocket target_socket, + const DOutputSocket::TargetSocketPathInfo &UNUSED(path_info)) { const DNode target_node = target_socket.node(); if (!this->node_states_.contains_as(target_node)) { /* The target node is not computed because it is not computed to the output. */ return; } output_state.potential_users += 1; - }, - {}); + }); if (output_state.potential_users == 0) { /* If it does not have any potential users, it is unused. It might become required again in * `schedule_initial_nodes`. */ @@ -1257,43 +1257,61 @@ class GeometryNodesEvaluator { { BLI_assert(value_to_forward.get() != nullptr); - Vector<DSocket> sockets_to_log_to; - sockets_to_log_to.append(from_socket); - - Vector<DInputSocket> to_sockets; - auto handle_target_socket_fn = [&, this](const DInputSocket to_socket) { - if (this->should_forward_to_socket(to_socket)) { - to_sockets.append(to_socket); - } - }; - auto handle_skipped_socket_fn = [&](const DSocket socket) { - sockets_to_log_to.append(socket); - }; - from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn); - LinearAllocator<> &allocator = local_allocators_.local(); - const CPPType &from_type = *value_to_forward.type(); - Vector<DInputSocket> to_sockets_same_type; - for (const DInputSocket &to_socket : to_sockets) { - const CPPType &to_type = *get_socket_cpp_type(to_socket); - if (from_type == to_type) { - /* All target sockets that do not need a conversion will be handled afterwards. */ - to_sockets_same_type.append(to_socket); - /* Multi input socket values are logged once all values are available. */ - if (!to_socket->is_multi_input_socket()) { - sockets_to_log_to.append(to_socket); - } - continue; - } - this->forward_to_socket_with_different_type( - allocator, value_to_forward, from_socket, to_socket, to_type); - } - - this->log_socket_value(sockets_to_log_to, value_to_forward); + Vector<DSocket> log_original_value_sockets; + Vector<DInputSocket> forward_original_value_sockets; + log_original_value_sockets.append(from_socket); + from_socket.foreach_target_socket( + [&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) { + if (!this->should_forward_to_socket(to_socket)) { + return; + } + BLI_assert(to_socket == path_info.sockets.last()); + GMutablePointer current_value = value_to_forward; + for (const DSocket &next_socket : path_info.sockets) { + const DNode next_node = next_socket.node(); + const bool is_last_socket = to_socket == next_socket; + const bool do_conversion_if_necessary = is_last_socket || + next_node->is_group_output_node() || + (next_node->is_group_node() && + !next_node->is_muted()); + if (do_conversion_if_necessary) { + const CPPType &next_type = *get_socket_cpp_type(next_socket); + if (*current_value.type() != next_type) { + void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); + this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); + if (current_value.get() != value_to_forward.get()) { + current_value.destruct(); + } + current_value = {next_type, buffer}; + } + } + if (current_value.get() == value_to_forward.get()) { + /* Log the original value at the current socket. */ + log_original_value_sockets.append(next_socket); + } + else { + /* Multi-input sockets are logged when all values are available. */ + if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) { + /* Log the converted value at the socket. */ + this->log_socket_value({next_socket}, current_value); + } + } + } + if (current_value.get() == value_to_forward.get()) { + /* The value has not been converted, so forward the original value. */ + forward_original_value_sockets.append(to_socket); + } + else { + /* The value has been converted. */ + this->add_value_to_input_socket(to_socket, from_socket, current_value); + } + }); + this->log_socket_value(log_original_value_sockets, value_to_forward); this->forward_to_sockets_with_same_type( - allocator, to_sockets_same_type, value_to_forward, from_socket); + allocator, forward_original_value_sockets, value_to_forward, from_socket); } bool should_forward_to_socket(const DInputSocket socket) @@ -1312,27 +1330,6 @@ class GeometryNodesEvaluator { return target_input_state.usage != ValueUsage::Unused; } - void forward_to_socket_with_different_type(LinearAllocator<> &allocator, - const GPointer value_to_forward, - const DOutputSocket from_socket, - const DInputSocket to_socket, - const CPPType &to_type) - { - const CPPType &from_type = *value_to_forward.type(); - - /* Allocate a buffer for the converted value. */ - void *buffer = allocator.allocate(to_type.size(), to_type.alignment()); - GMutablePointer value{to_type, buffer}; - - this->convert_value(from_type, to_type, value_to_forward.get(), buffer); - - /* Multi input socket values are logged once all values are available. */ - if (!to_socket->is_multi_input_socket()) { - this->log_socket_value({to_socket}, value); - } - this->add_value_to_input_socket(to_socket, from_socket, value); - } - void forward_to_sockets_with_same_type(LinearAllocator<> &allocator, Span<DInputSocket> to_sockets, GMutablePointer value_to_forward, diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index e903e3c9255..895f7ef6d5b 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -158,8 +158,19 @@ class DOutputSocket : public DSocket { DInputSocket get_corresponding_group_node_input() const; DInputSocket get_active_corresponding_group_output_socket() const; - void foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn, - FunctionRef<void(DSocket)> skipped_fn) const; + struct TargetSocketPathInfo { + /** All sockets on the path from the current to the final target sockets, excluding `this`. */ + Vector<DSocket, 16> sockets; + }; + + using ForeachTargetSocketFn = + FunctionRef<void(DInputSocket, const TargetSocketPathInfo &path_info)>; + + void foreach_target_socket(ForeachTargetSocketFn target_fn) const; + + private: + void foreach_target_socket(ForeachTargetSocketFn target_fn, + TargetSocketPathInfo &path_info) const; }; class DerivedNodeTree { diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index f7279cf7524..fb12157f147 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -231,45 +231,90 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c /* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes * and node groups are handled by this function. Target sockets are on the nodes that use the value - * from this socket. The `skipped_fn` function is called for sockets that have been skipped during - * the search for target sockets (e.g. reroutes). */ -void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn, - FunctionRef<void(DSocket)> skipped_fn) const + * from this socket. */ +void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const { - for (const SocketRef *skipped_socket : socket_ref_->logically_linked_skipped_sockets()) { - skipped_fn.call_safe({context_, skipped_socket}); - } - for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) { - const NodeRef &linked_node = linked_socket->node(); - DInputSocket linked_dsocket{context_, linked_socket}; + TargetSocketPathInfo path_info; + this->foreach_target_socket(target_fn, path_info); +} - if (linked_node.is_group_output_node()) { +void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, + TargetSocketPathInfo &path_info) const +{ + for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) { + if (link->is_muted()) { + continue; + } + const DInputSocket &linked_socket{context_, &link->to()}; + if (!linked_socket->is_available()) { + continue; + } + const DNode linked_node = linked_socket.node(); + if (linked_node->is_reroute_node()) { + const DInputSocket reroute_input = linked_socket; + const DOutputSocket reroute_output = linked_node.output(0); + path_info.sockets.append(reroute_input); + path_info.sockets.append(reroute_output); + reroute_output.foreach_target_socket(target_fn, path_info); + path_info.sockets.pop_last(); + path_info.sockets.pop_last(); + } + else if (linked_node->is_muted()) { + for (const InternalLinkRef *internal_link : linked_node->internal_links()) { + if (&internal_link->from() != linked_socket.socket_ref()) { + continue; + } + /* The internal link only forwards the first incoming link. */ + if (linked_socket->is_multi_input_socket()) { + if (linked_socket->directly_linked_links()[0] == link) { + continue; + } + } + const DInputSocket mute_input = linked_socket; + const DOutputSocket mute_output{context_, &internal_link->to()}; + path_info.sockets.append(mute_input); + path_info.sockets.append(mute_output); + mute_output.foreach_target_socket(target_fn, path_info); + path_info.sockets.pop_last(); + path_info.sockets.pop_last(); + break; + } + } + else if (linked_node->is_group_output_node()) { if (context_->is_root()) { /* This is a group output in the root node group. */ - target_fn(linked_dsocket); + path_info.sockets.append(linked_socket); + target_fn(linked_socket, path_info); + path_info.sockets.pop_last(); } else { /* Follow the links going out of the group node in the parent node group. */ - DOutputSocket socket_in_parent_group = - linked_dsocket.get_corresponding_group_node_output(); - skipped_fn.call_safe(linked_dsocket); - skipped_fn.call_safe(socket_in_parent_group); - socket_in_parent_group.foreach_target_socket(target_fn, skipped_fn); + const DOutputSocket socket_in_parent_group = + linked_socket.get_corresponding_group_node_output(); + path_info.sockets.append(linked_socket); + path_info.sockets.append(socket_in_parent_group); + socket_in_parent_group.foreach_target_socket(target_fn, path_info); + path_info.sockets.pop_last(); + path_info.sockets.pop_last(); } } - else if (linked_node.is_group_node()) { + else if (linked_node->is_group_node()) { /* Follow the links within the nested node group. */ - Vector<DOutputSocket> sockets_in_group = - linked_dsocket.get_corresponding_group_input_sockets(); - skipped_fn.call_safe(linked_dsocket); - for (DOutputSocket socket_in_group : sockets_in_group) { - skipped_fn.call_safe(socket_in_group); - socket_in_group.foreach_target_socket(target_fn, skipped_fn); + path_info.sockets.append(linked_socket); + const Vector<DOutputSocket> sockets_in_group = + linked_socket.get_corresponding_group_input_sockets(); + for (const DOutputSocket &socket_in_group : sockets_in_group) { + path_info.sockets.append(socket_in_group); + socket_in_group.foreach_target_socket(target_fn, path_info); + path_info.sockets.pop_last(); } + path_info.sockets.pop_last(); } else { /* The normal case: just use the linked input socket as target. */ - target_fn(linked_dsocket); + path_info.sockets.append(linked_socket); + target_fn(linked_socket, path_info); + path_info.sockets.pop_last(); } } } |