Nodes: cache node declaration on node

Previously, it was necessary to rebuild the node declaration
every time it was used. Now it is cached per node for easy
and fast access.

For more details on what this is, look at the comment in
`DNA_node_types.h`.

Differential Revision: https://developer.blender.org/D12471
This commit is contained in:
Jacques Lucke 2021-09-14 16:34:31 +02:00
parent dee0b56b92
commit edaeec3e72
5 changed files with 61 additions and 9 deletions

View File

@ -731,6 +731,8 @@ void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
void nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
/* Node Clipboard */
void BKE_node_clipboard_init(const struct bNodeTree *ntree);
void BKE_node_clipboard_clear(void);

View File

@ -653,6 +653,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
BLO_read_list(reader, &ntree->nodes);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->typeinfo = nullptr;
node->declaration = nullptr;
BLO_read_list(reader, &node->inputs);
BLO_read_list(reader, &node->outputs);
@ -1014,10 +1015,8 @@ IDTypeInfo IDType_ID_NT = {
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
{
if (ntype->declare != nullptr) {
blender::nodes::NodeDeclaration node_decl;
blender::nodes::NodeDeclarationBuilder builder{node_decl};
ntype->declare(builder);
node_decl.build(*ntree, *node);
nodeDeclarationEnsure(ntree, node);
node->declaration->build(*ntree, *node);
return;
}
bNodeSocketTemplate *sockdef;
@ -2216,6 +2215,10 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree,
bNodeLink *link_dst, *link_src;
*node_dst = *node_src;
/* Reset the declaration of the new node. */
node_dst->declaration = nullptr;
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
if (unique_name) {
@ -3103,6 +3106,8 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
MEM_freeN(node->prop);
}
delete node->declaration;
MEM_freeN(node);
if (ntree) {
@ -3933,6 +3938,21 @@ int nodeSocketLinkLimit(const bNodeSocket *sock)
return sock->limit;
}
/**
* If the node implements a `declare` function, this function makes sure that `node->declaration`
* is up to date.
*/
void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node)
{
if (node->typeinfo->declare == nullptr) {
return;
}
node->declaration = new blender::nodes::NodeDeclaration();
blender::nodes::NodeDeclarationBuilder builder{*node->declaration};
node->typeinfo->declare(builder);
}
/* ************** Node Clipboard *********** */
#define USE_NODE_CB_VALIDATE

View File

@ -216,6 +216,16 @@ typedef enum eNodeSocketFlag {
SOCK_HIDE_LABEL = (1 << 12),
} eNodeSocketFlag;
/** Workaround to forward-declare C++ type in C header. */
#ifdef __cplusplus
namespace blender::nodes {
class NodeDeclaration;
}
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
#else
typedef struct NodeDeclarationHandle NodeDeclarationHandle;
#endif
/* TODO: Limit data in bNode to what we want to see saved. */
typedef struct bNode {
struct bNode *next, *prev, *new_node;
@ -315,6 +325,26 @@ typedef struct bNode {
* needs to be a float to feed GPU_uniform.
*/
float sss_id;
/**
* 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;
} bNode;
/* node->flag */

View File

@ -60,6 +60,8 @@ class NodeDeclaration {
Span<SocketDeclarationPtr> inputs() const;
Span<SocketDeclarationPtr> outputs() const;
MEM_CXX_CLASS_ALLOC_FUNCS("NodeDeclaration")
};
class NodeDeclarationBuilder {

View File

@ -269,11 +269,9 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
return;
}
if (ntype->declare != nullptr) {
blender::nodes::NodeDeclaration node_decl;
blender::nodes::NodeDeclarationBuilder builder{node_decl};
ntype->declare(builder);
if (!node_decl.matches(*node)) {
refresh_node(*ntree, *node, node_decl, do_id_user);
nodeDeclarationEnsure(ntree, node);
if (!node->declaration->matches(*node)) {
refresh_node(*ntree, *node, *node->declaration, do_id_user);
}
return;
}