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:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2020-02-12 14:48:44 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2020-02-15 22:33:16 +0300
commit007f1b74a67302fb4c164eb26969419434a98aee (patch)
treef56ba0eecbbc11fc22e6a47aa0d76582e553e3da /source/blender/gpu/intern/gpu_node_graph.c
parent6701db773e660e5306e305a1b10f8ea52955f06b (diff)
Cleanup: split off code from gpu_codegen.c into smaller files
Diffstat (limited to 'source/blender/gpu/intern/gpu_node_graph.c')
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c562
1 files changed, 562 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
new file mode 100644
index 00000000000..432c2d773b5
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -0,0 +1,562 @@
+/*
+ * 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) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Intermediate node graph for generating GLSL shaders.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "gpu_material_library.h"
+#include "gpu_node_graph.h"
+
+/* Node Link Functions */
+
+static GPUNodeLink *gpu_node_link_create(void)
+{
+ GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink");
+ link->users++;
+
+ return link;
+}
+
+static void gpu_node_link_free(GPUNodeLink *link)
+{
+ link->users--;
+
+ if (link->users < 0) {
+ fprintf(stderr, "gpu_node_link_free: negative refcount\n");
+ }
+
+ if (link->users == 0) {
+ if (link->output) {
+ link->output->link = NULL;
+ }
+ MEM_freeN(link);
+ }
+}
+
+/* Node Functions */
+
+static GPUNode *gpu_node_create(const char *name)
+{
+ GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode");
+
+ node->name = name;
+
+ return node;
+}
+
+static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType type)
+{
+ GPUInput *input;
+ GPUNode *outnode;
+ const char *name;
+
+ if (link->link_type == GPU_NODE_LINK_OUTPUT) {
+ outnode = link->output->node;
+ name = outnode->name;
+ input = outnode->inputs.first;
+
+ if ((STR_ELEM(name, "set_value", "set_rgb", "set_rgba")) && (input->type == type)) {
+ input = MEM_dupallocN(outnode->inputs.first);
+ if (input->link) {
+ input->link->users++;
+ }
+ BLI_addtail(&node->inputs, input);
+ return;
+ }
+ }
+
+ input = MEM_callocN(sizeof(GPUInput), "GPUInput");
+ input->node = node;
+ input->type = type;
+
+ switch (link->link_type) {
+ case GPU_NODE_LINK_BUILTIN:
+ input->source = GPU_SOURCE_BUILTIN;
+ input->builtin = link->builtin;
+ break;
+ case GPU_NODE_LINK_OUTPUT:
+ input->source = GPU_SOURCE_OUTPUT;
+ input->link = link;
+ link->users++;
+ break;
+ case GPU_NODE_LINK_COLORBAND:
+ input->source = GPU_SOURCE_TEX;
+ input->coba = link->coba;
+ break;
+ case GPU_NODE_LINK_IMAGE_BLENDER:
+ case GPU_NODE_LINK_IMAGE_TILEMAP:
+ input->source = GPU_SOURCE_TEX;
+ input->ima = link->ima;
+ input->iuser = link->iuser;
+ break;
+ case GPU_NODE_LINK_ATTR:
+ input->source = GPU_SOURCE_ATTR;
+ input->attr_type = link->attr_type;
+ BLI_strncpy(input->attr_name, link->attr_name, sizeof(input->attr_name));
+ break;
+ case GPU_NODE_LINK_CONSTANT:
+ input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT;
+ break;
+ case GPU_NODE_LINK_UNIFORM:
+ input->source = GPU_SOURCE_UNIFORM;
+ break;
+ default:
+ break;
+ }
+
+ if (ELEM(input->source, GPU_SOURCE_CONSTANT, GPU_SOURCE_UNIFORM)) {
+ memcpy(input->vec, link->data, type * sizeof(float));
+ }
+
+ if (link->link_type != GPU_NODE_LINK_OUTPUT) {
+ MEM_freeN(link);
+ }
+ BLI_addtail(&node->inputs, input);
+}
+
+static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type)
+{
+ switch (type) {
+ /* For now INT is supported as float. */
+ case SOCK_INT:
+ case SOCK_FLOAT:
+ return "set_value";
+ case SOCK_VECTOR:
+ return "set_rgb";
+ case SOCK_RGBA:
+ return "set_rgba";
+ default:
+ BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype");
+ return NULL;
+ }
+}
+
+/**
+ * Link stack uniform buffer.
+ * This is called for the input/output sockets that are note connected.
+ */
+static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat,
+ bNode *node,
+ GPUNodeStack *stack,
+ const int index,
+ const eNodeSocketInOut in_out)
+{
+ bNodeSocket *socket;
+
+ if (in_out == SOCK_IN) {
+ socket = BLI_findlink(&node->inputs, index);
+ }
+ else {
+ socket = BLI_findlink(&node->outputs, index);
+ }
+
+ BLI_assert(socket != NULL);
+ BLI_assert(socket->in_out == in_out);
+
+ if ((socket->flag & SOCK_HIDE_VALUE) == 0) {
+ GPUNodeLink *link;
+ switch (socket->type) {
+ case SOCK_FLOAT: {
+ bNodeSocketValueFloat *socket_data = socket->default_value;
+ link = GPU_uniform(&socket_data->value);
+ break;
+ }
+ case SOCK_VECTOR: {
+ bNodeSocketValueVector *socket_data = socket->default_value;
+ link = GPU_uniform(socket_data->value);
+ break;
+ }
+ case SOCK_RGBA: {
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ link = GPU_uniform(socket_data->value);
+ break;
+ }
+ default:
+ return NULL;
+ break;
+ }
+
+ if (in_out == SOCK_IN) {
+ GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link);
+ }
+ return link;
+ }
+ return NULL;
+}
+
+static void gpu_node_input_socket(
+ GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
+{
+ if (sock->link) {
+ gpu_node_input_link(node, sock->link, sock->type);
+ }
+ else if ((material != NULL) &&
+ (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != NULL)) {
+ gpu_node_input_link(node, sock->link, sock->type);
+ }
+ else {
+ gpu_node_input_link(node, GPU_constant(sock->vec), sock->type);
+ }
+}
+
+static void gpu_node_output(GPUNode *node, const eGPUType type, GPUNodeLink **link)
+{
+ GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput");
+
+ output->type = type;
+ output->node = node;
+
+ if (link) {
+ *link = output->link = gpu_node_link_create();
+ output->link->link_type = GPU_NODE_LINK_OUTPUT;
+ output->link->output = output;
+
+ /* note: the caller owns the reference to the link, GPUOutput
+ * merely points to it, and if the node is destroyed it will
+ * set that pointer to NULL */
+ }
+
+ BLI_addtail(&node->outputs, output);
+}
+
+/* Creating Inputs */
+
+GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_ATTR;
+ link->attr_name = name;
+ /* Fall back to the UV layer, which matches old behavior. */
+ if (type == CD_AUTO_FROM_NAME && name[0] == '\0') {
+ link->attr_type = CD_MTFACE;
+ }
+ else {
+ link->attr_type = type;
+ }
+ return link;
+}
+
+GPUNodeLink *GPU_constant(float *num)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_CONSTANT;
+ link->data = num;
+ return link;
+}
+
+GPUNodeLink *GPU_uniform(float *num)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_UNIFORM;
+ link->data = num;
+ return link;
+}
+
+GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_IMAGE_BLENDER;
+ link->ima = ima;
+ link->iuser = iuser;
+ return link;
+}
+
+GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_COLORBAND;
+ link->coba = gpu_material_ramp_texture_row_set(mat, size, pixels, row);
+ MEM_freeN(pixels);
+ return link;
+}
+
+GPUNodeLink *GPU_builtin(eGPUBuiltin builtin)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_BUILTIN;
+ link->builtin = builtin;
+ return link;
+}
+
+/* Creating Nodes */
+
+bool GPU_link(GPUMaterial *mat, const char *name, ...)
+{
+ GSet *used_libraries = gpu_material_used_libraries(mat);
+ GPUNode *node;
+ GPUFunction *function;
+ GPUNodeLink *link, **linkptr;
+ va_list params;
+ int i;
+
+ function = gpu_material_library_use_function(used_libraries, name);
+ if (!function) {
+ fprintf(stderr, "GPU failed to find function %s\n", name);
+ return false;
+ }
+
+ node = gpu_node_create(name);
+
+ va_start(params, name);
+ for (i = 0; i < function->totparam; i++) {
+ if (function->paramqual[i] != FUNCTION_QUAL_IN) {
+ linkptr = va_arg(params, GPUNodeLink **);
+ gpu_node_output(node, function->paramtype[i], linkptr);
+ }
+ else {
+ link = va_arg(params, GPUNodeLink *);
+ gpu_node_input_link(node, link, function->paramtype[i]);
+ }
+ }
+ va_end(params);
+
+ gpu_material_add_node(mat, node);
+
+ return true;
+}
+
+bool GPU_stack_link(GPUMaterial *material,
+ bNode *bnode,
+ const char *name,
+ GPUNodeStack *in,
+ GPUNodeStack *out,
+ ...)
+{
+ GSet *used_libraries = gpu_material_used_libraries(material);
+ GPUNode *node;
+ GPUFunction *function;
+ GPUNodeLink *link, **linkptr;
+ va_list params;
+ int i, totin, totout;
+
+ function = gpu_material_library_use_function(used_libraries, name);
+ if (!function) {
+ fprintf(stderr, "GPU failed to find function %s\n", name);
+ return false;
+ }
+
+ node = gpu_node_create(name);
+ totin = 0;
+ totout = 0;
+
+ if (in) {
+ for (i = 0; !in[i].end; i++) {
+ if (in[i].type != GPU_NONE) {
+ gpu_node_input_socket(material, bnode, node, &in[i], i);
+ totin++;
+ }
+ }
+ }
+
+ if (out) {
+ for (i = 0; !out[i].end; i++) {
+ if (out[i].type != GPU_NONE) {
+ gpu_node_output(node, out[i].type, &out[i].link);
+ totout++;
+ }
+ }
+ }
+
+ va_start(params, out);
+ for (i = 0; i < function->totparam; i++) {
+ if (function->paramqual[i] != FUNCTION_QUAL_IN) {
+ if (totout == 0) {
+ linkptr = va_arg(params, GPUNodeLink **);
+ gpu_node_output(node, function->paramtype[i], linkptr);
+ }
+ else {
+ totout--;
+ }
+ }
+ else {
+ if (totin == 0) {
+ link = va_arg(params, GPUNodeLink *);
+ if (link->socket) {
+ gpu_node_input_socket(NULL, NULL, node, link->socket, -1);
+ }
+ else {
+ gpu_node_input_link(node, link, function->paramtype[i]);
+ }
+ }
+ else {
+ totin--;
+ }
+ }
+ }
+ va_end(params);
+
+ gpu_material_add_node(material, node);
+
+ return true;
+}
+
+GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat,
+ bNode *node,
+ GPUNodeStack *stack,
+ const int index)
+{
+ return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT);
+}
+
+/* Node Graph */
+
+static void gpu_inputs_free(ListBase *inputs)
+{
+ GPUInput *input;
+
+ for (input = inputs->first; input; input = input->next) {
+ if (input->link) {
+ gpu_node_link_free(input->link);
+ }
+ }
+
+ BLI_freelistN(inputs);
+}
+
+static void gpu_node_free(GPUNode *node)
+{
+ GPUOutput *output;
+
+ gpu_inputs_free(&node->inputs);
+
+ for (output = node->outputs.first; output; output = output->next) {
+ if (output->link) {
+ output->link->output = NULL;
+ gpu_node_link_free(output->link);
+ }
+ }
+
+ BLI_freelistN(&node->outputs);
+ MEM_freeN(node);
+}
+
+void gpu_node_graph_free(GPUNodeGraph *graph)
+{
+ GPUNode *node;
+
+ while ((node = BLI_pophead(&graph->nodes))) {
+ gpu_node_free(node);
+ }
+
+ gpu_inputs_free(&graph->inputs);
+ graph->outlink = NULL;
+ graph->builtins = 0;
+ memset(&graph->attrs, 0, sizeof(graph->attrs));
+}
+
+/* Extract Dynamic Inputs */
+
+void gpu_node_graph_extract_dynamic_inputs(GPUShader *shader, GPUNodeGraph *graph)
+{
+ GPUNode *node;
+ GPUInput *next, *input;
+
+ if (!shader) {
+ return;
+ }
+
+ while ((node = BLI_pophead(&graph->nodes))) {
+ for (input = node->inputs.first; input; input = next) {
+ next = input->next;
+
+ /* attributes don't need to be bound, they already have
+ * an id that the drawing functions will use. Builtins have
+ * constant names. */
+ if (ELEM(input->source, GPU_SOURCE_ATTR, GPU_SOURCE_BUILTIN)) {
+ continue;
+ }
+
+ if (input->source == GPU_SOURCE_TEX) {
+ BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid);
+ }
+ else {
+ BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id);
+ }
+
+ if (input->source == GPU_SOURCE_TEX) {
+ if (input->bindtex) {
+ input->shaderloc = GPU_shader_get_uniform_ensure(shader, input->shadername);
+ /* extract nodes */
+ BLI_remlink(&node->inputs, input);
+ BLI_addtail(&graph->inputs, input);
+ }
+ }
+ }
+
+ gpu_node_free(node);
+ }
+}
+
+/* Prune Unused Nodes */
+
+static void gpu_nodes_tag(GPUNodeLink *link)
+{
+ GPUNode *node;
+ GPUInput *input;
+
+ if (!link->output) {
+ return;
+ }
+
+ node = link->output->node;
+ if (node->tag) {
+ return;
+ }
+
+ node->tag = true;
+ for (input = node->inputs.first; input; input = input->next) {
+ if (input->link) {
+ gpu_nodes_tag(input->link);
+ }
+ }
+}
+
+void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
+{
+ GPUNode *node, *next;
+
+ for (node = graph->nodes.first; node; node = node->next) {
+ node->tag = false;
+ }
+
+ gpu_nodes_tag(graph->outlink);
+
+ for (node = graph->nodes.first; node; node = next) {
+ next = node->next;
+
+ if (!node->tag) {
+ BLI_remlink(&graph->nodes, node);
+ gpu_node_free(node);
+ }
+ }
+}