From 6239e089cf8e826c7fb99fb8a2a77229f5ccdac3 Mon Sep 17 00:00:00 2001 From: Iliya Katueshenock Date: Fri, 18 Nov 2022 11:20:13 +0100 Subject: [PATCH] Nodes: cache children of frame nodes This allows for optimizations because one does not have to iterate over all nodes anymore to find all nodes within a frame. Differential Revision: https://developer.blender.org/D16106 --- source/blender/blenkernel/BKE_node.h | 4 +- source/blender/blenkernel/BKE_node_runtime.hh | 15 +++++ .../blender/blenkernel/BKE_node_tree_update.h | 2 + source/blender/blenkernel/intern/node.cc | 8 ++- .../blender/blenkernel/intern/node_runtime.cc | 66 ++++++++++++++----- .../blenkernel/intern/node_tree_update.cc | 6 ++ source/blender/editors/space_node/node_add.cc | 2 +- .../blender/editors/space_node/node_edit.cc | 12 ++-- .../blender/editors/space_node/node_group.cc | 6 +- .../editors/space_node/node_relationships.cc | 31 ++++----- source/blender/makesdna/DNA_node_types.h | 4 ++ source/blender/makesrna/intern/rna_nodetree.c | 5 +- 12 files changed, 113 insertions(+), 48 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 1a36f3be0b2..b6a6fd00b7e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -730,8 +730,8 @@ void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node); void nodeToView(const struct bNode *node, float x, float y, float *rx, float *ry); void nodeFromView(const struct bNode *node, float x, float y, float *rx, float *ry); bool nodeAttachNodeCheck(const struct bNode *node, const struct bNode *parent); -void nodeAttachNode(struct bNode *node, struct bNode *parent); -void nodeDetachNode(struct bNode *node); +void nodeAttachNode(struct bNodeTree *ntree, struct bNode *node, struct bNode *parent); +void nodeDetachNode(struct bNodeTree *ntree, struct bNode *node); void nodePositionRelative(struct bNode *from_node, struct bNode *to_node, diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index 65c801a087b..5a73dff67ce 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -84,6 +84,7 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { bool has_available_link_cycle = false; bool has_undefined_nodes_or_sockets = false; bNode *group_output_node = nullptr; + Vector root_frames; }; /** @@ -154,6 +155,7 @@ class bNodeRuntime : NonCopyable, NonMovable { int index_in_tree = -1; bool has_available_linked_inputs = false; bool has_available_linked_outputs = false; + Vector direct_children_in_frame; bNodeTree *owner_tree = nullptr; }; @@ -323,6 +325,12 @@ inline blender::Span bNodeTree::all_sockets() return this->runtime->sockets; } +inline blender::Span bNodeTree::root_frames() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->root_frames; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -439,6 +447,13 @@ inline blender::Span bNode::internal_links_span() const return this->runtime->internal_links; } +inline blender::Span bNode::direct_children_in_frame() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + BLI_assert(this->is_frame()); + return this->runtime->direct_children_in_frame; +} + inline const blender::nodes::NodeDeclaration *bNode::declaration() const { return this->runtime->declaration; diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h index 801ba22b3e9..eafcf0fb8a1 100644 --- a/source/blender/blenkernel/BKE_node_tree_update.h +++ b/source/blender/blenkernel/BKE_node_tree_update.h @@ -54,6 +54,8 @@ void BKE_ntree_update_tag_active_output_changed(struct bNodeTree *ntree); void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree); /** Used when the interface sockets/values have changed. */ void BKE_ntree_update_tag_interface(struct bNodeTree *ntree); +/** Used when change parent node. */ +void BKE_ntree_update_tag_parent_change(struct bNodeTree *ntree, struct bNode *node); /** Used when an id data block changed that might be used by nodes that need to be updated. */ void BKE_ntree_update_tag_id_changed(struct Main *bmain, struct ID *id); /** Used when an image user is updated that is used by any part of the node tree. */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 96165fb6209..c3b1470f820 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -2571,7 +2571,7 @@ bool nodeAttachNodeCheck(const bNode *node, const bNode *parent) return false; } -void nodeAttachNode(bNode *node, bNode *parent) +void nodeAttachNode(bNodeTree *ntree, bNode *node, bNode *parent) { BLI_assert(parent->type == NODE_FRAME); BLI_assert(nodeAttachNodeCheck(parent, node) == false); @@ -2580,11 +2580,12 @@ void nodeAttachNode(bNode *node, bNode *parent) nodeToView(node, 0.0f, 0.0f, &locx, &locy); node->parent = parent; + BKE_ntree_update_tag_parent_change(ntree, node); /* transform to parent space */ nodeFromView(parent, locx, locy, &node->locx, &node->locy); } -void nodeDetachNode(struct bNode *node) +void nodeDetachNode(bNodeTree *ntree, bNode *node) { if (node->parent) { BLI_assert(node->parent->type == NODE_FRAME); @@ -2595,6 +2596,7 @@ void nodeDetachNode(struct bNode *node) node->locx = locx; node->locy = locy; node->parent = nullptr; + BKE_ntree_update_tag_parent_change(ntree, node); } } @@ -2935,7 +2937,7 @@ static void node_unlink_attached(bNodeTree *ntree, bNode *parent) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->parent == parent) { - nodeDetachNode(node); + nodeDetachNode(ntree, node); } } } diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc index 4fb0e423a33..712a740bdb7 100644 --- a/source/blender/blenkernel/intern/node_runtime.cc +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -372,6 +372,36 @@ static void update_toposort(const bNodeTree &ntree, BLI_assert(tree_runtime.nodes.size() == r_sorted_nodes.size()); } +static void update_root_frames(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + Span nodes = tree_runtime.nodes; + + tree_runtime.root_frames.clear(); + + for (bNode *node : nodes) { + if (!node->parent && node->is_frame()) { + tree_runtime.root_frames.append(node); + } + } +} + +static void update_direct_frames_childrens(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + Span nodes = tree_runtime.nodes; + + for (bNode *node : nodes) { + node->runtime->direct_children_in_frame.clear(); + } + + for (bNode *node : nodes) { + if (const bNode *frame = node->parent) { + frame->runtime->direct_children_in_frame.append(node); + } + } +} + static void update_group_output_node(const bNodeTree &ntree) { bNodeTreeRuntime &tree_runtime = *ntree.runtime; @@ -403,22 +433,26 @@ static void ensure_topology_cache(const bNodeTree &ntree) update_socket_vectors_and_owner_node(ntree); update_internal_links(ntree); update_directly_linked_links_and_sockets(ntree); - threading::parallel_invoke([&]() { update_logical_origins(ntree); }, - [&]() { update_nodes_by_type(ntree); }, - [&]() { update_sockets_by_identifier(ntree); }, - [&]() { - update_toposort(ntree, - ToposortDirection::LeftToRight, - tree_runtime.toposort_left_to_right, - tree_runtime.has_available_link_cycle); - }, - [&]() { - bool dummy; - update_toposort(ntree, - ToposortDirection::RightToLeft, - tree_runtime.toposort_right_to_left, - dummy); - }); + threading::parallel_invoke( + tree_runtime.nodes.size() > 32, + [&]() { update_logical_origins(ntree); }, + [&]() { update_nodes_by_type(ntree); }, + [&]() { update_sockets_by_identifier(ntree); }, + [&]() { + update_toposort(ntree, + ToposortDirection::LeftToRight, + tree_runtime.toposort_left_to_right, + tree_runtime.has_available_link_cycle); + }, + [&]() { + bool dummy; + update_toposort(ntree, + ToposortDirection::RightToLeft, + tree_runtime.toposort_right_to_left, + dummy); + }, + [&]() { update_root_frames(ntree); }, + [&]() { update_direct_frames_childrens(ntree); }); update_group_output_node(ntree); tree_runtime.topology_cache_exists = true; }); diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 707bb83a3bc..7b6c7954508 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -44,6 +44,7 @@ enum eNodeTreeChangedFlag { NTREE_CHANGED_REMOVED_SOCKET = (1 << 7), NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8), NTREE_CHANGED_INTERNAL_LINK = (1 << 9), + NTREE_CHANGED_PARENT = (1 << 10), NTREE_CHANGED_ALL = -1, }; @@ -1704,6 +1705,11 @@ void BKE_ntree_update_tag_interface(bNodeTree *ntree) add_tree_tag(ntree, NTREE_CHANGED_INTERFACE); } +void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, bNode *node) +{ + add_node_tag(ntree, node, NTREE_CHANGED_PARENT); +} + void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id) { FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) { diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 41f70a6d8cf..c18a6bda5d0 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -205,7 +205,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) for (const int i : frame_nodes.index_range()) { bNode *frame_node = frame_nodes.last(i); if (BLI_rctf_isect_pt_v(&frame_node->totr, insert_point)) { - nodeAttachNode(reroute, frame_node); + nodeAttachNode(&ntree, reroute, frame_node); break; } } diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index fe3126a3c23..5197ed10db4 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -1319,7 +1319,7 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link) /** \name Node Duplicate Operator * \{ */ -static void node_duplicate_reparent_recursive(const Map &node_map, +static void node_duplicate_reparent_recursive(bNodeTree *ntree, const Map &node_map, bNode *node) { bNode *parent; @@ -1330,15 +1330,15 @@ static void node_duplicate_reparent_recursive(const Map for (parent = node->parent; parent; parent = parent->parent) { if (parent->flag & SELECT) { if (!(parent->flag & NODE_TEST)) { - node_duplicate_reparent_recursive(node_map, parent); + node_duplicate_reparent_recursive(ntree, node_map, parent); } break; } } /* reparent node copy to parent copy */ if (parent) { - nodeDetachNode(node_map.lookup(node)); - nodeAttachNode(node_map.lookup(node), node_map.lookup(parent)); + nodeDetachNode(ntree, node_map.lookup(node)); + nodeAttachNode(ntree, node_map.lookup(node), node_map.lookup(parent)); } } @@ -1432,7 +1432,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* reparent copied nodes */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) { - node_duplicate_reparent_recursive(node_map, node); + node_duplicate_reparent_recursive(ntree, node_map, node); } /* only has to check old nodes */ @@ -2269,7 +2269,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator * /*op*/) new_node->parent = node_map.lookup(new_node->parent); } else { - nodeDetachNode(new_node); + nodeDetachNode(ntree, new_node); } } } diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 329f78860a4..3aebd2669bd 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -488,7 +488,7 @@ static bool node_group_separate_selected( /* ensure valid parent pointers, detach if parent stays inside the group */ if (newnode->parent && !(newnode->parent->flag & NODE_SELECT)) { - nodeDetachNode(newnode); + nodeDetachNode(&ngroup, newnode); } /* migrate node */ @@ -842,7 +842,7 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, } if (node_group_make_use_node(*node->parent, gnode) && !node_group_make_use_node(*node, gnode)) { - nodeDetachNode(node); + nodeDetachNode(&ntree, node); } } @@ -865,7 +865,7 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, /* ensure valid parent pointers, detach if parent stays outside the group */ if (node->parent && !(node->parent->flag & NODE_SELECT)) { - nodeDetachNode(node); + nodeDetachNode(&ntree, node); } /* change node-collection membership */ diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 8eeba8727dc..d570e7ab9fc 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -1601,8 +1601,8 @@ static int node_parent_set_exec(bContext *C, wmOperator * /*op*/) continue; } if (node->flag & NODE_SELECT) { - nodeDetachNode(node); - nodeAttachNode(node, frame); + nodeDetachNode(&ntree, node); + nodeAttachNode(&ntree, node, frame); } } @@ -1637,7 +1637,8 @@ void NODE_OT_parent_set(wmOperatorType *ot) #define NODE_JOIN_DONE 1 #define NODE_JOIN_IS_DESCENDANT 2 -static void node_join_attach_recursive(bNode *node, +static void node_join_attach_recursive(bNodeTree &ntree, + bNode *node, bNode *frame, const Set &selected_nodes) { @@ -1649,7 +1650,7 @@ static void node_join_attach_recursive(bNode *node, else if (node->parent) { /* call recursively */ if (!(node->parent->done & NODE_JOIN_DONE)) { - node_join_attach_recursive(node->parent, frame, selected_nodes); + node_join_attach_recursive(ntree, node->parent, frame, selected_nodes); } /* in any case: if the parent is a descendant, so is the child */ @@ -1658,13 +1659,13 @@ static void node_join_attach_recursive(bNode *node, } else if (selected_nodes.contains(node)) { /* if parent is not an descendant of the frame, reattach the node */ - nodeDetachNode(node); - nodeAttachNode(node, frame); + nodeDetachNode(&ntree, node); + nodeAttachNode(&ntree, node, frame); node->done |= NODE_JOIN_IS_DESCENDANT; } } else if (selected_nodes.contains(node)) { - nodeAttachNode(node, frame); + nodeAttachNode(&ntree, node, frame); node->done |= NODE_JOIN_IS_DESCENDANT; } } @@ -1687,7 +1688,7 @@ static int node_join_exec(bContext *C, wmOperator * /*op*/) LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (!(node->done & NODE_JOIN_DONE)) { - node_join_attach_recursive(node, frame_node, selected_nodes); + node_join_attach_recursive(ntree, node, frame_node, selected_nodes); } } @@ -1760,7 +1761,7 @@ static int node_attach_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *e /* disallow moving a parent into its child */ if (nodeAttachNodeCheck(frame, node) == false) { /* attach all unparented nodes */ - nodeAttachNode(node, frame); + nodeAttachNode(&ntree, node, frame); } } else { @@ -1775,8 +1776,8 @@ static int node_attach_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *e if (parent) { /* disallow moving a parent into its child */ if (nodeAttachNodeCheck(frame, node) == false) { - nodeDetachNode(node); - nodeAttachNode(node, frame); + nodeDetachNode(&ntree, node); + nodeAttachNode(&ntree, node, frame); } } } @@ -1814,14 +1815,14 @@ void NODE_OT_attach(wmOperatorType *ot) #define NODE_DETACH_DONE 1 #define NODE_DETACH_IS_DESCENDANT 2 -static void node_detach_recursive(bNode *node) +static void node_detach_recursive(bNodeTree &ntree, bNode *node) { node->done |= NODE_DETACH_DONE; if (node->parent) { /* call recursively */ if (!(node->parent->done & NODE_DETACH_DONE)) { - node_detach_recursive(node->parent); + node_detach_recursive(ntree, node->parent); } /* in any case: if the parent is a descendant, so is the child */ @@ -1830,7 +1831,7 @@ static void node_detach_recursive(bNode *node) } else if (node->flag & NODE_SELECT) { /* if parent is not a descendant of a selected node, detach */ - nodeDetachNode(node); + nodeDetachNode(&ntree, node); node->done |= NODE_DETACH_IS_DESCENDANT; } } @@ -1854,7 +1855,7 @@ static int node_detach_exec(bContext *C, wmOperator * /*op*/) */ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (!(node->done & NODE_DETACH_DONE)) { - node_detach_recursive(node); + node_detach_recursive(ntree, node); } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 3161238dc2e..1eecc5a1c86 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -407,6 +407,8 @@ typedef struct bNode { /** 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; + /** If node is frame, will return all children nodes. */ + blender::Span direct_children_in_frame() const; /** Node tree this node belongs to. */ const bNodeTree &owner_tree() const; #endif @@ -650,6 +652,8 @@ typedef struct bNodeTree { /** Efficient lookup of all nodes with a specific type. */ blender::Span nodes_by_type(blender::StringRefNull type_idname); blender::Span nodes_by_type(blender::StringRefNull type_idname) const; + /** Frame nodes without any parents. */ + blender::Span root_frames() const; /** * 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 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index c32e5b7d4db..854d5840ac7 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2333,6 +2333,7 @@ static void rna_Node_parent_set(PointerRNA *ptr, { bNode *node = ptr->data; bNode *parent = value.data; + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; if (parent) { /* XXX only Frame node allowed for now, @@ -2348,9 +2349,9 @@ static void rna_Node_parent_set(PointerRNA *ptr, } } - nodeDetachNode(node); + nodeDetachNode(ntree, node); if (parent) { - nodeAttachNode(node, parent); + nodeAttachNode(ntree, node, parent); } }