Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-04-01 16:14:53 +0300
committerJacques Lucke <jacques@blender.org>2021-04-01 16:14:53 +0300
commit2a2a4c8a27d4c9941a4fadcdc76379acb73e83d1 (patch)
tree765f6b8bd547473201a2324090da63c52ddb08bb /source/blender/nodes/intern/node_exec.cc
parentb00727950c28c31563426ea3c8c745b2c67e042d (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.cc336
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;
+}