diff options
author | Jacques Lucke <jacques@blender.org> | 2021-04-01 16:14:53 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-04-01 16:14:53 +0300 |
commit | 2a2a4c8a27d4c9941a4fadcdc76379acb73e83d1 (patch) | |
tree | 765f6b8bd547473201a2324090da63c52ddb08bb /source/blender/nodes/intern/node_exec.cc | |
parent | b00727950c28c31563426ea3c8c745b2c67e042d (diff) |
Cleanup: move node_exec.c to c++
Doing this, because it might make it easier to replace the implementation
of `bNodeInstanceHash`.
Diffstat (limited to 'source/blender/nodes/intern/node_exec.cc')
-rw-r--r-- | source/blender/nodes/intern/node_exec.cc | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc new file mode 100644 index 00000000000..bd9b398880c --- /dev/null +++ b/source/blender/nodes/intern/node_exec.cc @@ -0,0 +1,336 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup nodes + */ + +#include "DNA_node_types.h" + +#include "BLI_listbase.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_node.h" + +#include "MEM_guardedalloc.h" + +#include "node_exec.h" +#include "node_util.h" + +/* supported socket types in old nodes */ +int node_exec_socket_use_stack(bNodeSocket *sock) +{ + /* NOTE: INT supported as FLOAT. Only for EEVEE. */ + return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); +} + +/* for a given socket, find the actual stack entry */ +bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock) +{ + if (stack && sock && sock->stack_index >= 0) { + return stack + sock->stack_index; + } + return nullptr; +} + +void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out) +{ + bNodeSocket *sock; + + /* build pointer stack */ + if (in) { + for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { + *(in++) = node_get_socket_stack(stack, sock); + } + } + + if (out) { + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { + *(out++) = node_get_socket_stack(stack, sock); + } + } +} + +static void node_init_input_index(bNodeSocket *sock, int *index) +{ + /* Only consider existing link if from socket is valid! */ + if (sock->link && !(sock->link->flag & NODE_LINK_MUTED) && sock->link->fromsock && + sock->link->fromsock->stack_index >= 0) { + sock->stack_index = sock->link->fromsock->stack_index; + } + else { + if (node_exec_socket_use_stack(sock)) { + sock->stack_index = (*index)++; + } + else { + sock->stack_index = -1; + } + } +} + +static void node_init_output_index(bNodeSocket *sock, int *index, ListBase *internal_links) +{ + if (internal_links) { + bNodeLink *link; + /* copy the stack index from internally connected input to skip the node */ + for (link = (bNodeLink *)internal_links->first; link; link = link->next) { + if (link->tosock == sock) { + sock->stack_index = link->fromsock->stack_index; + /* set the link pointer to indicate that this socket + * should not overwrite the stack value! + */ + sock->link = link; + break; + } + } + /* if not internally connected, assign a new stack index anyway to avoid bad stack access */ + if (!link) { + if (node_exec_socket_use_stack(sock)) { + sock->stack_index = (*index)++; + } + else { + sock->stack_index = -1; + } + } + } + else { + if (node_exec_socket_use_stack(sock)) { + sock->stack_index = (*index)++; + } + else { + sock->stack_index = -1; + } + } +} + +/* basic preparation of socket stacks */ +static struct bNodeStack *setup_stack(bNodeStack *stack, + bNodeTree *ntree, + bNode *node, + bNodeSocket *sock) +{ + bNodeStack *ns = node_get_socket_stack(stack, sock); + if (!ns) { + return nullptr; + } + + /* don't mess with remote socket stacks, these are initialized by other nodes! */ + if (sock->link && !(sock->link->flag & NODE_LINK_MUTED)) { + return ns; + } + + ns->sockettype = sock->type; + + switch (sock->type) { + case SOCK_FLOAT: + ns->vec[0] = node_socket_get_float(ntree, node, sock); + break; + case SOCK_VECTOR: + node_socket_get_vector(ntree, node, sock, ns->vec); + break; + case SOCK_RGBA: + node_socket_get_color(ntree, node, sock, ns->vec); + break; + } + + return ns; +} + +bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, + bNodeTree *ntree, + bNodeInstanceKey parent_key) +{ + bNodeTreeExec *exec; + bNode *node; + bNodeExec *nodeexec; + bNodeInstanceKey nodekey; + bNodeSocket *sock; + bNodeStack *ns; + int index; + bNode **nodelist; + int totnodes, n; + /* XXX texnodes have threading issues with muting, have to disable it there ... */ + + /* ensure all sock->link pointers and node levels are correct */ + /* Using global main here is likely totally wrong, not sure what to do about that one though... + * We cannot even check ntree is in global main, + * since most of the time it won't be (thanks to ntree design)!!! */ + ntreeUpdateTree(G.main, ntree); + + /* get a dependency-sorted list of nodes */ + ntreeGetDependencyList(ntree, &nodelist, &totnodes); + + /* XXX could let callbacks do this for specialized data */ + exec = (bNodeTreeExec *)MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data"); + /* backpointer to node tree */ + exec->nodetree = ntree; + + /* set stack indices */ + index = 0; + for (n = 0; n < totnodes; n++) { + node = nodelist[n]; + + /* init node socket stack indexes */ + for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { + node_init_input_index(sock, &index); + } + + if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { + node_init_output_index(sock, &index, &node->internal_links); + } + } + else { + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { + node_init_output_index(sock, &index, nullptr); + } + } + } + + /* allocated exec data pointers for nodes */ + exec->totnodes = totnodes; + exec->nodeexec = (bNodeExec *)MEM_callocN(exec->totnodes * sizeof(bNodeExec), + "node execution data"); + /* allocate data pointer for node stack */ + exec->stacksize = index; + exec->stack = (bNodeStack *)MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack"); + + /* all non-const results are considered inputs */ + for (n = 0; n < exec->stacksize; n++) { + exec->stack[n].hasinput = 1; + } + + /* prepare all nodes for execution */ + for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) { + node = nodeexec->node = nodelist[n]; + nodeexec->free_exec_fn = node->typeinfo->free_exec_fn; + + /* tag inputs */ + for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { + /* disable the node if an input link is invalid */ + if (sock->link && !(sock->link->flag & NODE_LINK_VALID)) { + node->need_exec = 0; + } + + ns = setup_stack(exec->stack, ntree, node, sock); + if (ns) { + ns->hasoutput = 1; + } + } + + /* tag all outputs */ + for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) { + /* ns = */ setup_stack(exec->stack, ntree, node, sock); + } + + nodekey = BKE_node_instance_key(parent_key, ntree, node); + nodeexec->data.preview = context->previews ? (bNodePreview *)BKE_node_instance_hash_lookup( + context->previews, nodekey) : + nullptr; + if (node->typeinfo->init_exec_fn) { + nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey); + } + } + + if (nodelist) { + MEM_freeN(nodelist); + } + + return exec; +} + +void ntree_exec_end(bNodeTreeExec *exec) +{ + bNodeExec *nodeexec; + int n; + + if (exec->stack) { + MEM_freeN(exec->stack); + } + + for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) { + if (nodeexec->free_exec_fn) { + nodeexec->free_exec_fn(nodeexec->data.data); + } + } + + if (exec->nodeexec) { + MEM_freeN(exec->nodeexec); + } + + MEM_freeN(exec); +} + +/**** Material/Texture trees ****/ + +bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread) +{ + ListBase *lb = &exec->threadstack[thread]; + bNodeThreadStack *nts; + + for (nts = (bNodeThreadStack *)lb->first; nts; nts = nts->next) { + if (!nts->used) { + nts->used = true; + break; + } + } + + if (!nts) { + nts = (bNodeThreadStack *)MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); + nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack); + nts->used = true; + BLI_addtail(lb, nts); + } + + return nts; +} + +void ntreeReleaseThreadStack(bNodeThreadStack *nts) +{ + nts->used = 0; +} + +bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *callerdata, int thread) +{ + bNodeStack *nsin[MAX_SOCKET] = {nullptr}; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET] = {nullptr}; /* arbitrary... watch this */ + bNodeExec *nodeexec; + bNode *node; + int n; + + /* nodes are presorted, so exec is in order of list */ + + for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) { + node = nodeexec->node; + if (node->need_exec) { + node_get_stack(node, nts->stack, nsin, nsout); + /* Handle muted nodes... + * If the mute func is not set, assume the node should never be muted, + * and hence execute it! + */ + if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) { + node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout); + } + } + } + + /* signal to that all went OK, for render */ + return true; +} |