Files
test/source/blender/blenkernel/BKE_node_tree_update.hh
Jacques Lucke d28cf7a469 Fix #134283: defer freeing tree/node/socket types
Currently, tree, node and socket types are always freed immediately when the
Python code unregisters them. This is problematic, because there may still be
references to those type pointers in evaluated data owned by potentially various
depsgraphs. It's not possible to change data in these depsgraphs, because they
may be independent from the original data and might be worked on by a separate
thread. So when the type pointers are freed directly, there will be a lot of
dangling pointers in evaluated copies. Since those are used to free the nodes,
there will be a crash when the depsgraph updates. In practice, this does not
happen that often, because typically custom node tree addons are not disabled
while in use. They still used to crash often, but only when Blender exits and
unregisters all types.

The solution is to just keep the typeinfo pointers alive and free them all at
the very end. This obviously has the downside that the list of pointers we need
to keep track of can grow endlessly, however in practice that doesn't really
happen under any normal circumstances.

I'm still getting some other crashes when enabling/disabling Sverchok while
testing, but not entirely reliably and also without this patch (the crash there
happens in RNA code). So some additional work will probably be needed later to
make this work properly in all cases.

Pull Request: https://projects.blender.org/blender/blender/pulls/134360
2025-02-11 17:25:10 +01:00

107 lines
4.3 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bke
*/
#include <functional>
#include <optional>
#include "BLI_span.hh"
struct ID;
struct ImageUser;
struct Main;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
struct bNodeTree;
/**
* Tag tree as changed without providing any more information about what has changed exactly.
* The update process has to assume that everything may have changed.
*
* Using one of the methods below to tag the tree after changes is preferred when possible.
*/
void BKE_ntree_update_tag_all(bNodeTree *ntree);
/**
* More specialized tag functions that may result in a more efficient update.
*/
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node);
void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node);
void BKE_ntree_update_tag_node_removed(bNodeTree *ntree);
void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node);
void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node);
void BKE_ntree_update_tag_node_type(bNodeTree *ntree, bNode *node);
void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket);
void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket);
void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket);
void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket);
void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree);
void BKE_ntree_update_tag_link_changed(bNodeTree *ntree);
void BKE_ntree_update_tag_link_removed(bNodeTree *ntree);
void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *link);
void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *link);
/** Used when the a new output node becomes active and therefore changes the output. */
void BKE_ntree_update_tag_active_output_changed(bNodeTree *ntree);
/** Used after file loading when run-time data on the tree has not been initialized yet. */
void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree);
/** Used when change parent node. */
void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, 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(Main *bmain, ID *id);
/** Used when an image user is updated that is used by any part of the node tree. */
void BKE_ntree_update_tag_image_user_changed(bNodeTree *ntree, ImageUser *iuser);
struct NodeTreeUpdateExtraParams {
/**
* Called for every tree that has been changed during the update. This can be used to send
* notifiers to trigger redraws or depsgraph updates.
*/
std::function<void(bNodeTree &, ID &owner)> tree_changed_fn;
/**
* Called for every tree whose output value may have changed based on the provided update tags.
* This can be used to tag the depsgraph if necessary.
*/
std::function<void(bNodeTree &, ID &owner)> tree_output_changed_fn;
};
/**
* Updates the given bmain to ensure invariants related to node trees (for example that group nodes
* have sockets that correspond to the referenced node tree).
*
* \param bmain: Used to e.g. find node trees that depend on a modified node tree and thus have to
* be modified too.
* \param modified_trees: Optional filter for node trees that have been modified. Passing this in
* may make the update faster by avoiding having to iterate over all node trees.
* \param params: Additional parameters that allow the caller to properly tag the depsgraph and
* sent notifiers.
*/
void BKE_ntree_update(Main &bmain,
std::optional<blender::Span<bNodeTree *>> modified_trees = std::nullopt,
const NodeTreeUpdateExtraParams &params = {});
/**
* Same as #BKE_ntree_update but with a simpler API for the case when only a single tree has been
* modified.
*/
void BKE_ntree_update_after_single_tree_change(Main &bmain,
bNodeTree &modified_tree,
const NodeTreeUpdateExtraParams &params = {});
/**
* Can be used to update trees locally, without affecting other trees. For example, when building a
* temporary node tree that is not in bmain.
*/
void BKE_ntree_update_without_main(bNodeTree &tree);