diff options
author | Jacques Lucke <jacques@blender.org> | 2022-09-20 14:21:03 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-09-20 14:21:16 +0300 |
commit | 2b4cb893e7ebb33c24c7413ba0ff10eeb78bddfe (patch) | |
tree | 54ad42003882414a851a4dcbdae1bce366ac4304 /source/blender | |
parent | 22efaa2e7be9a605d6b1b043041dcbe4cb0bc969 (diff) |
Fix T101214: hidden link can cause cycle in node tree
Links that are linked to unavailable sockets should be ignored.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_node_runtime.hh | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node_runtime.cc | 34 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node_tree_update.cc | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 5 | ||||
-rw-r--r-- | source/blender/nodes/intern/derived_node_tree.cc | 2 | ||||
-rw-r--r-- | source/blender/nodes/intern/geometry_nodes_lazy_function.cc | 6 |
6 files changed, 42 insertions, 24 deletions
diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index c3e0460bdb1..65c801a087b 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -81,7 +81,7 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { Vector<bNode *> toposort_left_to_right; Vector<bNode *> toposort_right_to_left; Vector<bNode *> group_nodes; - bool has_link_cycle = false; + bool has_available_link_cycle = false; bool has_undefined_nodes_or_sockets = false; bNode *group_output_node = nullptr; }; @@ -152,8 +152,8 @@ class bNodeRuntime : NonCopyable, NonMovable { Map<StringRefNull, bNodeSocket *> inputs_by_identifier; Map<StringRefNull, bNodeSocket *> outputs_by_identifier; int index_in_tree = -1; - bool has_linked_inputs = false; - bool has_linked_outputs = false; + bool has_available_linked_inputs = false; + bool has_available_linked_outputs = false; bNodeTree *owner_tree = nullptr; }; @@ -269,10 +269,10 @@ inline blender::Span<bNode *> bNodeTree::group_nodes() return this->runtime->group_nodes; } -inline bool bNodeTree::has_link_cycle() const +inline bool bNodeTree::has_available_link_cycle() const { BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); - return this->runtime->has_link_cycle; + return this->runtime->has_available_link_cycle; } inline bool bNodeTree::has_undefined_nodes_or_sockets() const @@ -455,6 +455,11 @@ inline bool bNodeLink::is_muted() const return this->flag & NODE_LINK_MUTED; } +inline bool bNodeLink::is_available() const +{ + return this->fromsock->is_available() && this->tosock->is_available(); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc index 8b5b8bbc8b7..4fb0e423a33 100644 --- a/source/blender/blenkernel/intern/node_runtime.cc +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -123,15 +123,17 @@ static void update_directly_linked_links_and_sockets(const bNodeTree &ntree) socket->runtime->directly_linked_links.clear(); socket->runtime->directly_linked_sockets.clear(); } - node->runtime->has_linked_inputs = false; - node->runtime->has_linked_outputs = false; + node->runtime->has_available_linked_inputs = false; + node->runtime->has_available_linked_outputs = false; } for (bNodeLink *link : tree_runtime.links) { link->fromsock->runtime->directly_linked_links.append(link); link->fromsock->runtime->directly_linked_sockets.append(link->tosock); link->tosock->runtime->directly_linked_links.append(link); - link->fromnode->runtime->has_linked_outputs = true; - link->tonode->runtime->has_linked_inputs = true; + if (link->is_available()) { + link->fromnode->runtime->has_available_linked_outputs = true; + link->tonode->runtime->has_available_linked_inputs = true; + } } for (bNodeSocket *socket : tree_runtime.input_sockets) { if (socket->flag & SOCK_MULTI_INPUT) { @@ -168,7 +170,10 @@ static void find_logical_origins_for_socket_recursive( links_to_check = links_to_check.take_front(1); } for (bNodeLink *link : links_to_check) { - if (link->flag & NODE_LINK_MUTED) { + if (link->is_muted()) { + continue; + } + if (!link->is_available()) { continue; } bNodeSocket &origin_socket = *link->fromsock; @@ -285,14 +290,20 @@ static void toposort_from_start_node(const ToposortDirection direction, break; } bNodeSocket &socket = *sockets[item.socket_index]; - const Span<bNodeSocket *> linked_sockets = socket.runtime->directly_linked_sockets; - if (item.link_index == linked_sockets.size()) { + const Span<bNodeLink *> linked_links = socket.runtime->directly_linked_links; + if (item.link_index == linked_links.size()) { /* All links connected to this socket have already been visited. */ item.socket_index++; item.link_index = 0; continue; } - bNodeSocket &linked_socket = *linked_sockets[item.link_index]; + bNodeLink &link = *linked_links[item.link_index]; + if (!link.is_available()) { + /* Ignore unavailable links. */ + item.link_index++; + continue; + } + bNodeSocket &linked_socket = *socket.runtime->directly_linked_sockets[item.link_index]; bNode &linked_node = *linked_socket.runtime->owner_node; ToposortNodeState &linked_node_state = node_states[linked_node.runtime->index_in_tree]; if (linked_node_state.is_done) { @@ -337,8 +348,9 @@ static void update_toposort(const bNodeTree &ntree, /* Ignore nodes that are done already. */ continue; } - if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs : - node->runtime->has_linked_inputs) { + if ((direction == ToposortDirection::LeftToRight) ? + node->runtime->has_available_linked_outputs : + node->runtime->has_available_linked_inputs) { /* Ignore non-start nodes. */ continue; } @@ -398,7 +410,7 @@ static void ensure_topology_cache(const bNodeTree &ntree) update_toposort(ntree, ToposortDirection::LeftToRight, tree_runtime.toposort_left_to_right, - tree_runtime.has_link_cycle); + tree_runtime.has_available_link_cycle); }, [&]() { bool dummy; diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index dcb6666317f..f9bab0959c9 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -1388,7 +1388,7 @@ class NodeTreeMainUpdater { uint32_t get_combined_socket_topology_hash(const bNodeTree &tree, Span<const bNodeSocket *> sockets) { - if (tree.has_link_cycle()) { + if (tree.has_available_link_cycle()) { /* Return dummy value when the link has any cycles. The algorithm below could be improved to * handle cycles more gracefully. */ return 0; @@ -1404,7 +1404,7 @@ class NodeTreeMainUpdater { Array<uint32_t> get_socket_topology_hashes(const bNodeTree &tree, Span<const bNodeSocket *> sockets) { - BLI_assert(!tree.has_link_cycle()); + BLI_assert(!tree.has_available_link_cycle()); Array<std::optional<uint32_t>> hash_by_socket_id(tree.all_sockets().size()); Stack<const bNodeSocket *> sockets_to_check = sockets; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 7832541e360..06e14c3134b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -505,6 +505,7 @@ typedef struct bNodeLink { #ifdef __cplusplus bool is_muted() const; + bool is_available() const; #endif } bNodeLink; @@ -655,12 +656,12 @@ typedef struct bNodeTree { /** * Cached toposort of all nodes. If there are cycles, the returned array is not actually a * toposort. However, if a connected component does not contain a cycle, this component is sorted - * correctly. Use #has_link_cycle to check for cycles. + * correctly. Use #has_available_link_cycle to check for cycles. */ blender::Span<const bNode *> toposort_left_to_right() const; blender::Span<const bNode *> toposort_right_to_left() const; /** True when there are any cycles in the node tree. */ - bool has_link_cycle() const; + bool has_available_link_cycle() const; /** * True when there are nodes or sockets in the node tree that don't use a known type. This can * happen when nodes don't exist in the current Blender version that existed in the version where diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index e8e0f0fa61c..2ea80008af8 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -58,7 +58,7 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) bool DerivedNodeTree::has_link_cycles() const { for (const bNodeTree *btree : used_btrees_) { - if (btree->has_link_cycle()) { + if (btree->has_available_link_cycle()) { return true; } } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index af6861a59c0..718aaef5680 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1044,10 +1044,10 @@ struct GeometryNodesLazyFunctionGraphBuilder { if (link->is_muted()) { continue; } - const bNodeSocket &to_bsocket = *link->tosock; - if (!to_bsocket.is_available()) { + if (!link->is_available()) { continue; } + const bNodeSocket &to_bsocket = *link->tosock; const CPPType *to_type = get_socket_cpp_type(to_bsocket); if (to_type == nullptr) { continue; @@ -1258,7 +1258,7 @@ const GeometryNodesLazyFunctionGraphInfo *ensure_geometry_nodes_lazy_function_gr const bNodeTree &btree) { btree.ensure_topology_cache(); - if (btree.has_link_cycle()) { + if (btree.has_available_link_cycle()) { return nullptr; } |