Core: add concept of invariants in original DNA data
This patch adds a new `BKE_main_ensure_invariants` function. For now it only ensures node-tree related invariants, but more may be added over time. The already existing `ED_node_tree_propagate_change` now internally calls `BKE_main_ensure_invariants`. We can probably remove this indirection at some point and call the new function directly, but for now it is kept to keep this patch small. This is based on a recent discussion in the Core module meeting: https://devtalk.blender.org/t/2024-12-12-core-meeting/38074 ```cpp /** * Makes sure that invariants in original DNA data are maintained after changes. * * This function has to be idempotent, i.e. after calling it once, additional calls should not * modify DNA data further. If it would, it would imply that this function does more than * maintaining invariants. * * This has to be called after any kind of change to original DNA data that may be involved in some * of the maintained invariants. It's possible to do multiple changes in a row and then fixing all * invariants with a single call in the end. Obviously, the invariants are not maintained in the * meantime then and functions relying on them might not work. * * If nothing is changed, this function does nothing and it should not be slower than checking a * flag on every data-block in the given bmain. * * Sometimes, it is known that only a single or very few data-blocks have been changed (e.g. when a * node has been inserted in a node tree). Passing in #modified_ids can speed up the function * because it may avoid the need to iterate over all data-blocks to find modified data-blocks. * * Examples of maintained invariants: * - Group nodes need to have the correct sockets based on the referenced node group. * - The geometry nodes modifier needs to have the correct inputs based on the referenced group. */ void BKE_main_ensure_invariants(Main &bmain, std::optional<blender::Span<ID *>> modified_ids = std::nullopt); ``` This also adds `windowmanager` as a dependency of `blenkernel` to be able to send notifiers. Pull Request: https://projects.blender.org/blender/blender/pulls/132023
This commit is contained in:
37
source/blender/blenkernel/BKE_main_invariants.hh
Normal file
37
source/blender/blenkernel/BKE_main_invariants.hh
Normal file
@@ -0,0 +1,37 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_span.hh"
|
||||
#include <optional>
|
||||
|
||||
struct Main;
|
||||
struct ID;
|
||||
|
||||
/**
|
||||
* Makes sure that invariants in original DNA data are maintained after changes.
|
||||
*
|
||||
* This function has to be idempotent, i.e. after calling it once, additional calls should not
|
||||
* modify DNA data further. If it would, it would imply that this function does more than
|
||||
* maintaining invariants.
|
||||
*
|
||||
* This has to be called after any kind of change to original DNA data that may be involved in some
|
||||
* of the maintained invariants. It's possible to do multiple changes in a row and then fixing all
|
||||
* invariants with a single call in the end. Obviously, the invariants are not maintained in the
|
||||
* meantime then and functions relying on them might not work.
|
||||
*
|
||||
* If nothing is changed, this function does nothing and it should not be slower than checking a
|
||||
* flag on every data-block in the given bmain.
|
||||
*
|
||||
* Sometimes, it is known that only a single or very few data-blocks have been changed (e.g. when a
|
||||
* node has been inserted in a node tree). Passing in #modified_ids can speed up the function
|
||||
* because it may avoid the need to iterate over all data-blocks to find modified data-blocks.
|
||||
*
|
||||
* Examples of maintained invariants:
|
||||
* - Group nodes need to have the correct sockets based on the referenced node group.
|
||||
* - The geometry nodes modifier needs to have the correct inputs based on the referenced group.
|
||||
*/
|
||||
void BKE_main_ensure_invariants(Main &bmain,
|
||||
std::optional<blender::Span<ID *>> modified_ids = std::nullopt);
|
||||
@@ -10,6 +10,7 @@ set(INC
|
||||
../nodes/geometry/include
|
||||
../shader_fx
|
||||
../simulation
|
||||
../windowmanager
|
||||
../../../intern/eigen
|
||||
../../../intern/ghost
|
||||
../../../intern/iksolver/extern
|
||||
@@ -180,6 +181,7 @@ set(SRC
|
||||
intern/linestyle.cc
|
||||
intern/main.cc
|
||||
intern/main_idmap.cc
|
||||
intern/main_invariants.cc
|
||||
intern/main_namemap.cc
|
||||
intern/mask.cc
|
||||
intern/mask_evaluate.cc
|
||||
@@ -432,6 +434,7 @@ set(SRC
|
||||
BKE_linestyle.h
|
||||
BKE_main.hh
|
||||
BKE_main_idmap.hh
|
||||
BKE_main_invariants.hh
|
||||
BKE_main_namemap.hh
|
||||
BKE_mask.h
|
||||
BKE_material.hh
|
||||
|
||||
70
source/blender/blenkernel/intern/main_invariants.cc
Normal file
70
source/blender/blenkernel/intern/main_invariants.cc
Normal file
@@ -0,0 +1,70 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_main_invariants.hh"
|
||||
#include "BKE_node_tree_update.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
#include <optional>
|
||||
|
||||
static void send_notifiers_after_node_tree_change(ID *id, bNodeTree *ntree)
|
||||
{
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, id);
|
||||
|
||||
if (ntree->type == NTREE_SHADER && id != nullptr) {
|
||||
if (GS(id->name) == ID_MA) {
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
|
||||
}
|
||||
else if (GS(id->name) == ID_LA) {
|
||||
WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
|
||||
}
|
||||
else if (GS(id->name) == ID_WO) {
|
||||
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
|
||||
}
|
||||
}
|
||||
else if (ntree->type == NTREE_COMPOSIT) {
|
||||
WM_main_add_notifier(NC_SCENE | ND_NODES, id);
|
||||
}
|
||||
else if (ntree->type == NTREE_TEXTURE) {
|
||||
WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
|
||||
}
|
||||
else if (ntree->type == NTREE_GEOMETRY) {
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void propagate_node_tree_changes(Main &bmain,
|
||||
const std::optional<blender::Span<ID *>> modified_ids)
|
||||
{
|
||||
NodeTreeUpdateExtraParams params;
|
||||
params.tree_changed_fn = [](bNodeTree &ntree, ID &owner_id) {
|
||||
send_notifiers_after_node_tree_change(&owner_id, &ntree);
|
||||
DEG_id_tag_update(&ntree.id, ID_RECALC_SYNC_TO_EVAL);
|
||||
};
|
||||
params.tree_output_changed_fn = [](bNodeTree &ntree, ID & /*owner_id*/) {
|
||||
DEG_id_tag_update(&ntree.id, ID_RECALC_NTREE_OUTPUT);
|
||||
};
|
||||
|
||||
std::optional<blender::Vector<bNodeTree *>> modified_trees;
|
||||
if (modified_ids.has_value()) {
|
||||
modified_trees.emplace();
|
||||
for (ID *id : *modified_ids) {
|
||||
if (GS(id->name) == ID_NT) {
|
||||
modified_trees->append(reinterpret_cast<bNodeTree *>(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BKE_ntree_update(bmain, modified_trees, params);
|
||||
}
|
||||
|
||||
void BKE_main_ensure_invariants(Main &bmain, const std::optional<blender::Span<ID *>> modified_ids)
|
||||
{
|
||||
propagate_node_tree_changes(bmain, modified_ids);
|
||||
}
|
||||
@@ -78,6 +78,7 @@
|
||||
#include "BKE_lib_remap.hh"
|
||||
#include "BKE_main.hh" /* for Main */
|
||||
#include "BKE_main_idmap.hh"
|
||||
#include "BKE_main_invariants.hh"
|
||||
#include "BKE_main_namemap.hh"
|
||||
#include "BKE_material.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
@@ -3946,8 +3947,8 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
|
||||
* Proper fix involves first addressing #90610. */
|
||||
BKE_main_collections_parent_relations_rebuild(bfd->main);
|
||||
|
||||
/* Update node trees after re-generating overrides. */
|
||||
BKE_ntree_update(*bfd->main);
|
||||
/* Update invariants after re-generating overrides. */
|
||||
BKE_main_ensure_invariants(*bfd->main);
|
||||
|
||||
fd->reports->duration.lib_overrides = BLI_time_now_seconds() -
|
||||
fd->reports->duration.lib_overrides;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "BKE_image.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_main_invariants.hh"
|
||||
#include "BKE_material.hh"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_legacy_types.hh"
|
||||
@@ -460,32 +461,6 @@ bool composite_node_editable(bContext *C)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
|
||||
{
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, id);
|
||||
|
||||
if (ntree->type == NTREE_SHADER && id != nullptr) {
|
||||
if (GS(id->name) == ID_MA) {
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
|
||||
}
|
||||
else if (GS(id->name) == ID_LA) {
|
||||
WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
|
||||
}
|
||||
else if (GS(id->name) == ID_WO) {
|
||||
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
|
||||
}
|
||||
}
|
||||
else if (ntree->type == NTREE_COMPOSIT) {
|
||||
WM_main_add_notifier(NC_SCENE | ND_NODES, id);
|
||||
}
|
||||
else if (ntree->type == NTREE_TEXTURE) {
|
||||
WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
|
||||
}
|
||||
else if (ntree->type == NTREE_GEOMETRY) {
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::ed::space_node
|
||||
@@ -496,19 +471,11 @@ static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
|
||||
|
||||
void ED_node_tree_propagate_change(Main &bmain, bNodeTree *root_ntree)
|
||||
{
|
||||
NodeTreeUpdateExtraParams params;
|
||||
params.tree_changed_fn = [](bNodeTree &ntree, ID &owner_id) {
|
||||
blender::ed::space_node::send_notifiers_after_tree_change(&owner_id, &ntree);
|
||||
DEG_id_tag_update(&ntree.id, ID_RECALC_SYNC_TO_EVAL);
|
||||
};
|
||||
params.tree_output_changed_fn = [](bNodeTree &ntree, ID & /*owner_id*/) {
|
||||
DEG_id_tag_update(&ntree.id, ID_RECALC_NTREE_OUTPUT);
|
||||
};
|
||||
if (root_ntree) {
|
||||
BKE_ntree_update_after_single_tree_change(bmain, *root_ntree, params);
|
||||
BKE_main_ensure_invariants(bmain, {{&root_ntree->id}});
|
||||
}
|
||||
else {
|
||||
BKE_ntree_update(bmain, std::nullopt, params);
|
||||
BKE_main_ensure_invariants(bmain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user