Nodes: optimize freeing all nodes
We generally expect `bNodeTreeRuntime::nodes_by_id` to be valid at all times, so it also has to have the same order `bNodeTree.nodes`. When freeing a node, the entire vector set was rebuild currently to ensure that invariant. This leads O(n^2) behavior when all nodes are freed as is commonly the case with depsgraph copies etc. This patch implements an optimization where `nodes_by_id` is not rebuild if only the last node was removed. In this case, that not can just be popped from `nodes_by_id` without affecting the order of the other nodes. To use this optimization, the node tree freeing code now frees nodes in reverse order. Pull Request: https://projects.blender.org/blender/blender/pulls/143831
This commit is contained in:
@@ -271,7 +271,9 @@ static void ntree_free_data(ID *id)
|
||||
|
||||
BLI_freelistN(&ntree->links);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
|
||||
/* Iterate backwards because this allows for more efficient node deletion while keeping
|
||||
* bNodeTreeRuntime::nodes_by_id valid. */
|
||||
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNode *, node, &ntree->nodes) {
|
||||
node_free_node(ntree, *node);
|
||||
}
|
||||
|
||||
@@ -4094,8 +4096,17 @@ void node_free_node(bNodeTree *ntree, bNode &node)
|
||||
/* can be called for nodes outside a node tree (e.g. clipboard) */
|
||||
if (ntree) {
|
||||
BLI_remlink(&ntree->nodes, &node);
|
||||
/* Rebuild nodes #VectorSet which must have the same order as the list. */
|
||||
node_rebuild_id_vector(*ntree);
|
||||
|
||||
const bool was_last = ntree->runtime->nodes_by_id.as_span().last() == &node;
|
||||
if (was_last) {
|
||||
/* No need to rebuild the entire bNodeTreeRuntime::nodes_by_id when the removed node is the
|
||||
* last one. */
|
||||
ntree->runtime->nodes_by_id.pop();
|
||||
}
|
||||
else {
|
||||
/* Rebuild nodes #VectorSet which must have the same order as the list. */
|
||||
node_rebuild_id_vector(*ntree);
|
||||
}
|
||||
|
||||
/* texture node has bad habit of keeping exec data around */
|
||||
if (ntree->type == NTREE_TEXTURE && ntree->runtime->execdata) {
|
||||
|
||||
Reference in New Issue
Block a user