From 6a59cf053091dc45e0f94b829bee6c34cf940534 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 30 May 2022 15:31:13 +0200 Subject: Nodes: add separately allocated runtime data for nodes and sockets This is a follow up to rBbb0fc675822f313c5546a2498a162472c2571ecb. Now the same kind of run-time data is added to nodes and sockets. Differential Revision: https://developer.blender.org/D15060 --- source/blender/blenkernel/BKE_node_runtime.hh | 51 +++++++++++++++++++++- source/blender/blenkernel/intern/node.cc | 34 ++++++++++----- .../blender/blenkernel/intern/node_tree_update.cc | 18 ++++---- source/blender/editors/space_node/drawnode.cc | 5 ++- source/blender/editors/space_node/node_draw.cc | 8 ++-- .../editors/space_node/node_relationships.cc | 2 +- source/blender/makesdna/DNA_node_types.h | 42 +++++------------- source/blender/nodes/NOD_node_tree_ref.hh | 3 +- source/blender/nodes/intern/node_geometry_exec.cc | 2 +- source/blender/nodes/intern/node_socket.cc | 5 ++- .../nodes/intern/node_socket_declarations.cc | 7 +-- 11 files changed, 109 insertions(+), 68 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index c9c4577a2d4..c835279061c 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -9,7 +9,8 @@ namespace blender::nodes { struct FieldInferencingInterface; -} +struct NodeDeclaration; +} // namespace blender::nodes namespace blender::bke { @@ -37,4 +38,52 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { std::unique_ptr field_inferencing_interface; }; +/** + * Run-time data for every socket. This should only contain data that is somewhat persistent (i.e. + * data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in + * smaller scopes should generally be stored in separate arrays and/or maps. + */ +class bNodeSocketRuntime : NonCopyable, NonMovable { + public: + /** + * References a socket declaration that is owned by `node->declaration`. This is only runtime + * data. It has to be updated when the node declaration changes. + */ + const SocketDeclarationHandle *declaration = nullptr; + + /** #eNodeTreeChangedFlag. */ + uint32_t changed_flag = 0; +}; + +/** + * Run-time data for every node. This should only contain data that is somewhat persistent (i.e. + * data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in + * smaller scopes should generally be stored in separate arrays and/or maps. + */ +class bNodeRuntime : NonCopyable, NonMovable { + public: + /** + * Describes the desired interface of the node. This is run-time data only. + * The actual interface of the node may deviate from the declaration temporarily. + * It's possible to sync the actual state of the node to the desired state. Currently, this is + * only done when a node is created or loaded. + * + * In the future, we may want to keep more data only in the declaration, so that it does not have + * to be synced to other places that are stored in files. That especially applies to data that + * can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...). + * + * The declaration of a node can be recreated at any time when it is used. Caching it here is + * just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date, + * call #nodeDeclarationEnsure before using it. + * + * Currently, the declaration is the same for every node of the same type. Going forward, that is + * intended to change though. Especially when nodes become more dynamic with respect to how many + * sockets they have. + */ + NodeDeclarationHandle *declaration = nullptr; + + /** #eNodeTreeChangedFlag. */ + uint32_t changed_flag = 0; +}; + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 95a514ef474..cf50e8a3b43 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -95,6 +95,8 @@ using blender::Stack; using blender::StringRef; using blender::Vector; using blender::VectorSet; +using blender::bke::bNodeRuntime; +using blender::bke::bNodeSocketRuntime; using blender::bke::bNodeTreeRuntime; using blender::nodes::FieldInferencingInterface; using blender::nodes::InputSocketFieldType; @@ -662,7 +664,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) BLO_read_data_address(reader, &sock->default_attribute_name); sock->total_inputs = 0; /* Clear runtime data set before drawing. */ sock->cache = nullptr; - sock->declaration = nullptr; + sock->runtime = MEM_new(__func__); } void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) @@ -682,8 +684,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) BLO_read_list(reader, &ntree->nodes); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + node->runtime = MEM_new(__func__); node->typeinfo = nullptr; - node->declaration = nullptr; BLO_read_list(reader, &node->inputs); BLO_read_list(reader, &node->outputs); @@ -1514,6 +1516,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree, unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier)); bNodeSocket *sock = MEM_cnew("sock"); + sock->runtime = MEM_new(__func__); sock->in_out = in_out; BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); @@ -1919,6 +1922,7 @@ static void node_socket_free(bNodeSocket *sock, const bool do_id_user) } MEM_freeN(sock->default_value); } + MEM_delete(sock->runtime); } void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock) @@ -2124,6 +2128,7 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node) bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) { bNode *node = MEM_cnew("new node"); + node->runtime = MEM_new(__func__); BLI_addtail(&ntree->nodes, node); BLI_strncpy(node->idname, idname, sizeof(node->idname)); @@ -2161,6 +2166,7 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag) { + sock_dst->runtime = MEM_new(__func__); if (sock_src->prop) { sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); } @@ -2193,6 +2199,8 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree, bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__); *node_dst = node_src; + node_dst->runtime = MEM_new(__func__); + /* Can be called for nodes outside a node tree (e.g. clipboard). */ if (dst_tree) { if (unique_name) { @@ -2253,7 +2261,6 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree, } /* Reset the declaration of the new node. */ - node_dst->declaration = nullptr; nodeDeclarationEnsure(dst_tree, node_dst); return node_dst; @@ -2972,9 +2979,10 @@ static void node_free_node(bNodeTree *ntree, bNode *node) } if (node->typeinfo->declaration_is_dynamic) { - delete node->declaration; + delete node->runtime->declaration; } + MEM_delete(node->runtime); MEM_freeN(node); if (ntree) { @@ -3066,6 +3074,7 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), } MEM_freeN(sock->default_value); } + MEM_delete(sock->runtime); } static void free_localized_node_groups(bNodeTree *ntree) @@ -3292,6 +3301,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree, } bNodeSocket *sock = MEM_cnew("socket template"); + sock->runtime = MEM_new(__func__); BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); sock->in_out = in_out; sock->type = SOCK_CUSTOM; /* int type undefined by default */ @@ -3679,34 +3689,34 @@ static void update_socket_declarations(ListBase *sockets, int index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { const SocketDeclaration &socket_decl = *declarations[index]; - socket->declaration = &socket_decl; + socket->runtime->declaration = &socket_decl; } } void nodeSocketDeclarationsUpdate(bNode *node) { - BLI_assert(node->declaration != nullptr); - update_socket_declarations(&node->inputs, node->declaration->inputs()); - update_socket_declarations(&node->outputs, node->declaration->outputs()); + BLI_assert(node->runtime->declaration != nullptr); + update_socket_declarations(&node->inputs, node->runtime->declaration->inputs()); + update_socket_declarations(&node->outputs, node->runtime->declaration->outputs()); } bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node) { - if (node->declaration != nullptr) { + if (node->runtime->declaration != nullptr) { return false; } if (node->typeinfo->declare == nullptr) { return false; } if (node->typeinfo->declaration_is_dynamic) { - node->declaration = new blender::nodes::NodeDeclaration(); - blender::nodes::NodeDeclarationBuilder builder{*node->declaration}; + node->runtime->declaration = new blender::nodes::NodeDeclaration(); + blender::nodes::NodeDeclarationBuilder builder{*node->runtime->declaration}; node->typeinfo->declare(builder); } else { /* Declaration should have been created in #nodeRegisterType. */ BLI_assert(node->typeinfo->fixed_declaration != nullptr); - node->declaration = node->typeinfo->fixed_declaration; + node->runtime->declaration = node->typeinfo->fixed_declaration; } return true; } diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index d4b7f695ee1..019ab114b83 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -55,13 +55,13 @@ static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag) static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag) { add_tree_tag(ntree, flag); - node->changed_flag |= flag; + node->runtime->changed_flag |= flag; } static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag) { add_tree_tag(ntree, flag); - socket->changed_flag |= flag; + socket->runtime->changed_flag |= flag; } namespace blender::bke { @@ -1082,7 +1082,7 @@ class NodeTreeMainUpdater { if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } - if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { return true; } if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) { @@ -1542,12 +1542,12 @@ class NodeTreeMainUpdater { const NodeRef &node = in_out_socket.node(); const bNode &bnode = *node.bnode(); const bNodeSocket &bsocket = *in_out_socket.bsocket(); - if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) { + if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { return true; } - if (bnode.changed_flag != NTREE_CHANGED_NOTHING) { + if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) { const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 && - bnode.changed_flag == + bnode.runtime->changed_flag == NTREE_CHANGED_INTERNAL_LINK; if (!only_unused_internal_link_changed) { return true; @@ -1595,13 +1595,13 @@ class NodeTreeMainUpdater { { ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { - node->changed_flag = NTREE_CHANGED_NOTHING; + node->runtime->changed_flag = NTREE_CHANGED_NOTHING; node->update = 0; LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - socket->changed_flag = NTREE_CHANGED_NOTHING; + socket->runtime->changed_flag = NTREE_CHANGED_NOTHING; } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { - socket->changed_flag = NTREE_CHANGED_NOTHING; + socket->runtime->changed_flag = NTREE_CHANGED_NOTHING; } } } diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index d5507619e0d..6806d715004 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -20,6 +20,7 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_scene.h" #include "BKE_tracking.h" @@ -1271,14 +1272,14 @@ static void node_file_output_socket_draw(bContext *C, static bool socket_needs_attribute_search(bNode &node, bNodeSocket &socket) { - if (node.declaration == nullptr) { + if (node.runtime->declaration == nullptr) { return false; } if (socket.in_out == SOCK_OUT) { return false; } const int socket_index = BLI_findindex(&node.inputs, &socket); - return node.declaration->inputs()[socket_index]->is_attribute_name(); + return node.runtime->declaration->inputs()[socket_index]->is_attribute_name(); } static void std_node_socket_draw( diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index f5048e0cc67..4d194dfbd38 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -982,8 +982,8 @@ static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket) return true; } - if (socket->declaration != nullptr) { - const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration; + if (socket->runtime->declaration != nullptr) { + const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration; return !socket_decl.description().is_empty(); } @@ -996,8 +996,8 @@ static char *node_socket_get_tooltip(bContext *C, bNodeSocket *socket) { std::stringstream output; - if (socket->declaration != nullptr) { - const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration; + if (socket->runtime->declaration != nullptr) { + const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration; blender::StringRef description = socket_decl.description(); if (!description.is_empty()) { output << TIP_(description.data()); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index c757fb46407..5796a712205 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -2048,7 +2048,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const nodes::NodeDeclaration *node_decl = node.declaration; + const nodes::NodeDeclaration *node_decl = node.runtime->declaration; if (node_decl != nullptr) { Span socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : node_decl->outputs(); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 0ac61d7d062..a0738883bf3 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -73,14 +73,20 @@ class SocketDeclaration; } // namespace blender::nodes namespace blender::bke { class bNodeTreeRuntime; -} +class bNodeRuntime; +class bNodeSocketRuntime; +} // namespace blender::bke using NodeDeclarationHandle = blender::nodes::NodeDeclaration; using SocketDeclarationHandle = blender::nodes::SocketDeclaration; using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; +using bNodeRuntimeHandle = blender::bke::bNodeRuntime; +using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; #else typedef struct NodeDeclarationHandle NodeDeclarationHandle; typedef struct SocketDeclarationHandle SocketDeclarationHandle; typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; +typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; +typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; #endif typedef struct bNodeSocket { @@ -174,15 +180,7 @@ typedef struct bNodeSocket { /** Custom data for inputs, only UI writes in this. */ bNodeStack ns DNA_DEPRECATED; - /** - * References a socket declaration that is owned by `node->declaration`. This is only runtime - * data. It has to be updated when the node declaration changes. - */ - const SocketDeclarationHandle *declaration; - - /** #eNodeTreeChangedFlag. */ - uint32_t changed_flag; - char _pad[4]; + bNodeSocketRuntimeHandle *runtime; } bNodeSocket; /** #bNodeSocket.type & #bNodeSocketType.type */ @@ -271,9 +269,7 @@ typedef struct bNode { /** Used as a boolean for execution. */ uint8_t need_exec; - char _pad2[5]; - /** #eNodeTreeChangedFlag. */ - uint32_t changed_flag; + char _pad2[1]; /** Custom user-defined color. */ float color[3]; @@ -336,25 +332,7 @@ typedef struct bNode { /** Used at runtime when iterating over node branches. */ char iter_flag; - /** - * Describes the desired interface of the node. This is run-time data only. - * The actual interface of the node may deviate from the declaration temporarily. - * It's possible to sync the actual state of the node to the desired state. Currently, this is - * only done when a node is created or loaded. - * - * In the future, we may want to keep more data only in the declaration, so that it does not have - * to be synced to other places that are stored in files. That especially applies to data that - * can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...). - * - * The declaration of a node can be recreated at any time when it is used. Caching it here is - * just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date, - * call #nodeDeclarationEnsure before using it. - * - * Currently, the declaration is the same for every node of the same type. Going forward, that is - * intended to change though. Especially when nodes become more dynamic with respect to how many - * sockets they have. - */ - NodeDeclarationHandle *declaration; + bNodeRuntimeHandle *runtime; } bNode; /* node->flag */ diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh index 61d1d11d859..257aa5f4110 100644 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ b/source/blender/nodes/NOD_node_tree_ref.hh @@ -41,6 +41,7 @@ #include "BLI_vector.hh" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "DNA_node_types.h" @@ -597,7 +598,7 @@ inline bNodeType *NodeRef::typeinfo() const inline const NodeDeclaration *NodeRef::declaration() const { nodeDeclarationEnsure(this->tree().btree(), bnode_); - return bnode_->declaration; + return bnode_->runtime->declaration; } inline int NodeRef::id() const diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 39d8c453e43..9aee3ddcce7 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -37,7 +37,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const { const SocketDeclaration &decl = - *provider_->dnode->input_by_identifier(identifier).bsocket()->declaration; + *provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration; const decl::Geometry *geo_decl = dynamic_cast(&decl); if (geo_decl == nullptr) { return; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 0ab446d8b0c..098f766589d 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -19,6 +19,7 @@ #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "DNA_collection_types.h" #include "DNA_material_types.h" @@ -261,8 +262,8 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user) } if (ntype->declare != nullptr) { nodeDeclarationEnsureOnOutdatedNode(ntree, node); - if (!node->declaration->matches(*node)) { - refresh_node(*ntree, *node, *node->declaration, do_id_user); + if (!node->runtime->declaration->matches(*node)) { + refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user); } nodeSocketDeclarationsUpdate(node); return; diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc index 06925761bc7..b9fb75f30c7 100644 --- a/source/blender/nodes/intern/node_socket_declarations.cc +++ b/source/blender/nodes/intern/node_socket_declarations.cc @@ -4,6 +4,7 @@ #include "NOD_socket_declarations_geometry.hh" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BLI_math_vector.h" @@ -33,14 +34,14 @@ static bool sockets_can_connect(const SocketDeclaration &socket_decl, return false; } - if (other_socket.declaration) { + if (other_socket.runtime->declaration) { if (socket_decl.in_out() == SOCK_IN) { - if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) { + if (!field_types_are_compatible(socket_decl, *other_socket.runtime->declaration)) { return false; } } else { - if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) { + if (!field_types_are_compatible(*other_socket.runtime->declaration, socket_decl)) { return false; } } -- cgit v1.2.3