diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 2361d902d61..7efc28a3ab3 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -690,6 +690,7 @@ void nodeRemoveNode(struct Main *bmain, void nodeDimensionsGet(const struct bNode *node, float *r_width, float *r_height); void nodeTagUpdateID(struct bNode *node); +void nodeInternalLinks(struct bNode *node, struct bNodeLink ***r_links, int *r_len); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index 60a9fec7776..831b5330a2f 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -186,10 +186,12 @@ class bNodeRuntime : NonCopyable, NonMovable { /** Offset that will be added to locx for insert offset animation. */ float anim_ofsx; + /** List of cached internal links (input to output), for muted nodes and operators. */ + Vector internal_links; + /** Only valid if #topology_cache_is_dirty is false. */ Vector inputs; Vector outputs; - Vector internal_links; Map inputs_by_identifier; Map outputs_by_identifier; int index_in_tree = -1; @@ -481,9 +483,8 @@ inline bool bNode::is_group_output() const return this->type == NODE_GROUP_OUTPUT; } -inline blender::Span bNode::internal_links_span() const +inline blender::Span bNode::internal_links() const { - BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); return this->runtime->internal_links; } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index b92dea6bfc6..81ee2bdd34b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -699,8 +699,6 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &node->prop); IDP_BlendDataRead(reader, &node->prop); - BLI_listbase_clear(&node->internal_links); - if (node->type == CMP_NODE_MOVIEDISTORTION) { /* Do nothing, this is runtime cache and hence handled by generic code using * `IDTypeInfo.foreach_cache` callback. */ @@ -1970,11 +1968,12 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree, } } - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node->internal_links) { + for (bNodeLink *link : node->runtime->internal_links) { if (link->fromsock == sock || link->tosock == sock) { - BLI_remlink(&node->internal_links, link); + node->runtime->internal_links.remove_first_occurrence_and_reorder(link); MEM_freeN(link); BKE_ntree_update_tag_node_internal_link(ntree, node); + break; } } @@ -1996,7 +1995,10 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) } } - BLI_freelistN(&node->internal_links); + for (bNodeLink *link : node->runtime->internal_links) { + MEM_freeN(link); + } + node->runtime->internal_links.clear(); LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { node_socket_free(sock, true); @@ -2304,14 +2306,14 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree, node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag); } - BLI_listbase_clear(&node_dst->internal_links); - LISTBASE_FOREACH (const bNodeLink *, src_link, &node_src.internal_links) { + node_dst->runtime->internal_links.clear(); + for (const bNodeLink *src_link : node_src.runtime->internal_links) { bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link); dst_link->fromnode = node_dst; dst_link->tonode = node_dst; dst_link->fromsock = socket_map.lookup(src_link->fromsock); dst_link->tosock = socket_map.lookup(src_link->tosock); - BLI_addtail(&node_dst->internal_links, dst_link); + node_dst->runtime->internal_links.append(dst_link); } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -2469,7 +2471,7 @@ static void adjust_multi_input_indices_after_removed_link(bNodeTree *ntree, void nodeInternalRelink(bNodeTree *ntree, bNode *node) { /* store link pointers in output sockets, for efficient lookup */ - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { + for (bNodeLink *link : node->runtime->internal_links) { link->tosock->link = link; } @@ -2977,7 +2979,10 @@ static void node_free_node(bNodeTree *ntree, bNode *node) MEM_freeN(sock); } - BLI_freelistN(&node->internal_links); + for (bNodeLink *link : node->runtime->internal_links) { + MEM_freeN(link); + } + node->runtime->internal_links.clear(); if (node->prop) { /* Remember, no ID user refcount management here! */ @@ -3763,6 +3768,12 @@ void nodeTagUpdateID(bNode *node) node->runtime->update |= NODE_UPDATE_ID; } +void nodeInternalLinks(bNode *node, bNodeLink ***r_links, int *r_len) +{ + *r_links = node->runtime->internal_links.data(); + *r_len = node->runtime->internal_links.size(); +} + /* ************** Node Clipboard *********** */ #define USE_NODE_CB_VALIDATE diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc index 712a740bdb7..61f0bab9fef 100644 --- a/source/blender/blenkernel/intern/node_runtime.cc +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -67,21 +67,6 @@ static void update_link_vector(const bNodeTree &ntree) } } -static void update_internal_links(const bNodeTree &ntree) -{ - bNodeTreeRuntime &tree_runtime = *ntree.runtime; - for (bNode *node : tree_runtime.nodes) { - node->runtime->internal_links.clear(); - for (bNodeSocket *socket : node->runtime->outputs) { - socket->runtime->internal_link_input = nullptr; - } - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - node->runtime->internal_links.append(link); - link->tosock->runtime->internal_link_input = link->fromsock; - } - } -} - static void update_socket_vectors_and_owner_node(const bNodeTree &ntree) { bNodeTreeRuntime &tree_runtime = *ntree.runtime; @@ -431,7 +416,6 @@ static void ensure_topology_cache(const bNodeTree &ntree) update_node_vector(ntree); update_link_vector(ntree); update_socket_vectors_and_owner_node(ntree); - update_internal_links(ntree); update_directly_linked_links_and_sockets(ntree); threading::parallel_invoke( tree_runtime.nodes.size() > 32, diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index d068e150f25..3100a242c7d 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -1137,7 +1137,7 @@ class NodeTreeMainUpdater { } } /* Rebuilt internal links if they have changed. */ - if (node->internal_links_span().size() != expected_internal_links.size()) { + if (node->runtime->internal_links.size() != expected_internal_links.size()) { this->update_internal_links_in_node(ntree, *node, expected_internal_links); } else { @@ -1145,7 +1145,7 @@ class NodeTreeMainUpdater { const bNodeSocket *from_socket = item.first; const bNodeSocket *to_socket = item.second; bool found = false; - for (const bNodeLink *internal_link : node->internal_links_span()) { + for (const bNodeLink *internal_link : node->runtime->internal_links) { if (from_socket == internal_link->fromsock && to_socket == internal_link->tosock) { found = true; } @@ -1192,7 +1192,9 @@ class NodeTreeMainUpdater { bNode &node, Span> links) { - BLI_freelistN(&node.internal_links); + for (bNodeLink *link : node.runtime->internal_links) { + MEM_freeN(link); + } for (const auto &item : links) { bNodeSocket *from_socket = item.first; bNodeSocket *to_socket = item.second; @@ -1202,7 +1204,7 @@ class NodeTreeMainUpdater { link->tonode = &node; link->tosock = to_socket; link->flag |= NODE_LINK_VALID; - BLI_addtail(&node.internal_links, link); + node.runtime->internal_links.append(link); } BKE_ntree_update_tag_node_internal_link(&ntree, &node); } diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 47a1f7f7241..504de311f7e 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -1707,26 +1707,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - if (!MAIN_VERSION_ATLEAST(bmain, 264, 6)) { - /* Fix for bug T32982, internal_links list could get corrupted from r51630 onward. - * Simply remove bad internal_links lists to avoid NULL pointers. - */ - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - bNode *node; - bNodeLink *link, *nextlink; - - for (node = ntree->nodes.first; node; node = node->next) { - for (link = node->internal_links.first; link; link = nextlink) { - nextlink = link->next; - if (!link->fromnode || !link->fromsock || !link->tonode || !link->tosock) { - BLI_remlink(&node->internal_links, link); - } - } - } - } - FOREACH_NODETREE_END; - } - if (!MAIN_VERSION_ATLEAST(bmain, 264, 7)) { /* convert tiles size from resolution and number of tiles */ { diff --git a/source/blender/compositor/intern/COM_NodeGraph.cc b/source/blender/compositor/intern/COM_NodeGraph.cc index b38ac804cf5..34a145f6bf5 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cc +++ b/source/blender/compositor/intern/COM_NodeGraph.cc @@ -6,6 +6,7 @@ #include "DNA_node_types.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "COM_Converter.h" #include "COM_Debug.h" @@ -180,8 +181,7 @@ void NodeGraph::add_proxies_mute(bNodeTree *b_ntree, bNodeInstanceKey key, bool is_active_group) { - for (bNodeLink *b_link = (bNodeLink *)b_node->internal_links.first; b_link; - b_link = b_link->next) { + for (const bNodeLink *b_link : b_node->internal_links()) { SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock, false); add_node(proxy, b_ntree, key, is_active_group); } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index c6b25ddad01..434c2168976 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -703,7 +703,7 @@ static void node_draw_mute_line(const bContext &C, { GPU_blend(GPU_BLEND_ALPHA); - LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) { + for (const bNodeLink *link : node.internal_links()) { if (!nodeLinkIsHidden(link)) { node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE, false); } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 67597b40406..515740335a0 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -320,8 +320,6 @@ typedef struct bNode { struct ID *id; /** Custom data, must be struct, for storage in file. */ void *storage; - /** List of cached internal links (input to output), for muted nodes and operators. */ - ListBase internal_links; /** Root offset for drawing (parent space). */ float locx, locy; @@ -349,6 +347,8 @@ typedef struct bNode { bool is_group_input() const; bool is_group_output() const; const blender::nodes::NodeDeclaration *declaration() const; + /** A span containing all internal links when the node is muted. */ + blender::Span internal_links() const; /* The following methods are only available when #bNodeTree.ensure_topology_cache has been * called. */ @@ -365,8 +365,6 @@ typedef struct bNode { /** Utility to get an output socket by its index. */ bNodeSocket &output_socket(int index); const bNodeSocket &output_socket(int index) const; - /** A span containing all internal links when the node is muted. */ - blender::Span internal_links_span() const; /** Lookup socket of this node by its identifier. */ const bNodeSocket &input_by_identifier(blender::StringRef identifier) const; const bNodeSocket &output_by_identifier(blender::StringRef identifier) const; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 5adb6f55763..891c74c114f 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2357,6 +2357,15 @@ static void rna_Node_parent_set(PointerRNA *ptr, } } +static void rna_Node_internal_links_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + bNode *node = ptr->data; + bNodeLink **begin; + int len; + nodeInternalLinks(node, &begin, &len); + rna_iterator_array_begin(iter, begin, sizeof(bNodeLink *), len, false, NULL); +} + static bool rna_Node_parent_poll(PointerRNA *ptr, PointerRNA value) { bNode *node = ptr->data; @@ -12243,7 +12252,15 @@ static void rna_def_node(BlenderRNA *brna) rna_def_node_sockets_api(brna, prop, SOCK_OUT); prop = RNA_def_property(srna, "internal_links", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "internal_links", NULL); + RNA_def_property_collection_funcs(prop, + "rna_Node_internal_links_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_dereference_get", + NULL, + NULL, + NULL, + NULL); RNA_def_property_struct_type(prop, "NodeLink"); RNA_def_property_ui_text( prop, "Internal Links", "Internal input-to-output connections for muting"); diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index 2ea80008af8..50fbf791536 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -236,7 +236,7 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } else if (linked_node->is_muted()) { - for (const bNodeLink *internal_link : linked_node->internal_links_span()) { + for (const bNodeLink *internal_link : linked_node->internal_links()) { if (internal_link->fromsock != linked_socket.bsocket()) { continue; } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index aa4e251b215..da994553a29 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -337,7 +337,7 @@ class LazyFunctionForMutedNode : public LazyFunction { input_by_output_index_.reinitialize(outputs_.size()); input_by_output_index_.fill(-1); - for (const bNodeLink *internal_link : node.internal_links_span()) { + for (const bNodeLink *internal_link : node.internal_links()) { const int input_i = r_used_inputs.first_index_of_try(internal_link->fromsock); const int output_i = r_used_outputs.first_index_of_try(internal_link->tosock); if (ELEM(-1, input_i, output_i)) { diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index e0364f20d01..53d6e2ea29e 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -69,32 +69,25 @@ static void node_init_input_index(bNodeSocket *sock, int *index) } } -static void node_init_output_index(bNodeSocket *sock, int *index, ListBase *internal_links) +static void node_init_output_index_muted(bNodeSocket *sock, + int *index, + const blender::Span internal_links) { - if (internal_links) { - bNodeLink *link; - /* copy the stack index from internally connected input to skip the node */ - for (link = (bNodeLink *)internal_links->first; link; link = link->next) { - if (link->tosock == sock) { - sock->stack_index = link->fromsock->stack_index; - /* set the link pointer to indicate that this socket - * should not overwrite the stack value! - */ - sock->link = link; - break; - } - } - /* if not internally connected, assign a new stack index anyway to avoid bad stack access */ - if (!link) { - if (node_exec_socket_use_stack(sock)) { - sock->stack_index = (*index)++; - } - else { - sock->stack_index = -1; - } + bNodeLink *link; + /* copy the stack index from internally connected input to skip the node */ + for (bNodeLink *iter_link : internal_links) { + if (iter_link->tosock == sock) { + sock->stack_index = iter_link->fromsock->stack_index; + /* set the link pointer to indicate that this socket + * should not overwrite the stack value! + */ + sock->link = iter_link; + link = iter_link; + break; } } - else { + /* if not internally connected, assign a new stack index anyway to avoid bad stack access */ + if (!link) { if (node_exec_socket_use_stack(sock)) { sock->stack_index = (*index)++; } @@ -104,6 +97,16 @@ static void node_init_output_index(bNodeSocket *sock, int *index, ListBase *inte } } +static void node_init_output_index(bNodeSocket *sock, int *index) +{ + if (node_exec_socket_use_stack(sock)) { + sock->stack_index = (*index)++; + } + else { + sock->stack_index = -1; + } +} + /* basic preparation of socket stacks */ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, @@ -178,12 +181,12 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { - node_init_output_index(sock, &index, &node->internal_links); + node_init_output_index_muted(sock, &index, node->runtime->internal_links); } } else { for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { - node_init_output_index(sock, &index, nullptr); + node_init_output_index(sock, &index); } } } diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 6d02ed7d553..02611bb675f 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -220,7 +220,7 @@ static void refresh_socket_list(bNodeTree &ntree, link->tosock = new_socket; } } - LISTBASE_FOREACH (bNodeLink *, internal_link, &node.internal_links) { + for (bNodeLink *internal_link : node.runtime->internal_links) { if (internal_link->fromsock == old_socket_with_same_identifier) { internal_link->fromsock = new_socket; }