Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/intern/gpu_codegen.c
| Show All 30 Lines | |||||
| * Convert material node-trees to GLSL. | * Convert material node-trees to GLSL. | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DNA_customdata_types.h" | #include "DNA_customdata_types.h" | ||||
| #include "DNA_image_types.h" | #include "DNA_image_types.h" | ||||
| #include "DNA_material_types.h" | #include "DNA_material_types.h" | ||||
| #include "DNA_node_types.h" | |||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_dynstr.h" | #include "BLI_dynstr.h" | ||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | ||||
| #include "GPU_extensions.h" | #include "GPU_extensions.h" | ||||
| #include "GPU_glew.h" | #include "GPU_glew.h" | ||||
| #include "GPU_material.h" | #include "GPU_material.h" | ||||
| #include "GPU_shader.h" | #include "GPU_shader.h" | ||||
| #include "GPU_texture.h" | #include "GPU_texture.h" | ||||
| #include "GPU_uniformbuffer.h" | |||||
| #include "BLI_sys_types.h" /* for intptr_t support */ | #include "BLI_sys_types.h" /* for intptr_t support */ | ||||
| #include "gpu_codegen.h" | #include "gpu_codegen.h" | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <stdarg.h> | #include <stdarg.h> | ||||
| ▲ Show 20 Lines • Show All 445 Lines • ▼ Show 20 Lines | for (output = node->outputs.first; output; output = output->next) | ||||
| /* set id for unique names of tmp variables storing output */ | /* set id for unique names of tmp variables storing output */ | ||||
| output->id = id++; | output->id = id++; | ||||
| } | } | ||||
| BLI_ghash_free(bindhash, NULL, NULL); | BLI_ghash_free(bindhash, NULL, NULL); | ||||
| BLI_ghash_free(definehash, NULL, NULL); | BLI_ghash_free(definehash, NULL, NULL); | ||||
| } | } | ||||
| static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) | /** | ||||
| * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO. | |||||
| */ | |||||
| static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, ListBase *nodes) | |||||
| { | { | ||||
| GPUNode *node; | GPUNode *node; | ||||
| GPUInput *input; | GPUInput *input; | ||||
| const char *name; | const char *name; | ||||
| int builtins = 0; | int builtins = 0; | ||||
| ListBase ubo_inputs = {NULL, NULL}; | |||||
| /* print uniforms */ | /* print uniforms */ | ||||
| for (node = nodes->first; node; node = node->next) { | for (node = nodes->first; node; node = node->next) { | ||||
| for (input = node->inputs.first; input; input = input->next) { | for (input = node->inputs.first; input; input = input->next) { | ||||
| if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) { | if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) { | ||||
| /* create exactly one sampler for each texture */ | /* create exactly one sampler for each texture */ | ||||
| if (codegen_input_has_texture(input) && input->bindtex) { | if (codegen_input_has_texture(input) && input->bindtex) { | ||||
| BLI_dynstr_appendf(ds, "uniform %s samp%d;\n", | BLI_dynstr_appendf(ds, "uniform %s samp%d;\n", | ||||
| Show All 15 Lines | for (input = node->inputs.first; input; input = input->next) { | ||||
| else { | else { | ||||
| BLI_dynstr_appendf(ds, "%s %s %s;\n", | BLI_dynstr_appendf(ds, "%s %s %s;\n", | ||||
| GLEW_VERSION_3_0 ? "in" : "varying", | GLEW_VERSION_3_0 ? "in" : "varying", | ||||
| GPU_DATATYPE_STR[input->type], name); | GPU_DATATYPE_STR[input->type], name); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (input->source == GPU_SOURCE_VEC_UNIFORM) { | else if (input->source == GPU_SOURCE_VEC_UNIFORM) { | ||||
| if (input->dynamicvec) { | if (input->dynamictype == GPU_DYNAMIC_UBO) { | ||||
| if (!input->link) { | |||||
| /* We handle the UBOuniforms separately. */ | |||||
| BLI_addtail(&ubo_inputs, BLI_genericNodeN(input)); | |||||
| } | |||||
| } | |||||
| else if (input->dynamicvec) { | |||||
| /* only create uniforms for dynamic vectors */ | /* only create uniforms for dynamic vectors */ | ||||
| BLI_dynstr_appendf(ds, "uniform %s unf%d;\n", | BLI_dynstr_appendf(ds, "uniform %s unf%d;\n", | ||||
| GPU_DATATYPE_STR[input->type], input->id); | GPU_DATATYPE_STR[input->type], input->id); | ||||
| } | } | ||||
| else { | else { | ||||
| if (input->type != GPU_CLOSURE) { | if (input->type != GPU_CLOSURE) { | ||||
| /* for others use const so the compiler can do folding */ | /* for others use const so the compiler can do folding */ | ||||
| BLI_dynstr_appendf(ds, "const %s cons%d = ", | BLI_dynstr_appendf(ds, "const %s cons%d = ", | ||||
| Show All 22 Lines | #ifdef WITH_OPENSUBDIV | ||||
| if (skip_opensubdiv) { | if (skip_opensubdiv) { | ||||
| BLI_dynstr_appendf(ds, "#endif\n"); | BLI_dynstr_appendf(ds, "#endif\n"); | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Handle the UBO block separately. */ | |||||
| if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { | |||||
| GPU_material_create_uniform_buffer(material, &ubo_inputs); | |||||
| /* Inputs are sorted */ | |||||
| BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); | |||||
| for (LinkData *link = ubo_inputs.first; link; link = link->next) { | |||||
| input = link->data; | |||||
| BLI_dynstr_appendf(ds, "\tuniform %s unf%d;\n", | |||||
fclem: You don't need the uniform identifier here. | |||||
| GPU_DATATYPE_STR[input->type], input->id); | |||||
| } | |||||
| BLI_dynstr_append(ds, "};\n"); | |||||
| BLI_freelistN(&ubo_inputs); | |||||
| } | |||||
| BLI_dynstr_append(ds, "\n"); | BLI_dynstr_append(ds, "\n"); | ||||
| return builtins; | return builtins; | ||||
| } | } | ||||
| static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) | static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) | ||||
| { | { | ||||
| GPUNode *node; | GPUNode *node; | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | for (node = nodes->first; node; node = node->next) { | ||||
| BLI_dynstr_append(ds, ");\n"); | BLI_dynstr_append(ds, ");\n"); | ||||
| } | } | ||||
| BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id); | BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id); | ||||
| BLI_dynstr_append(ds, ";\n"); | BLI_dynstr_append(ds, ";\n"); | ||||
| } | } | ||||
| static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, bool use_new_shading) | static char *code_generate_fragment(GPUMaterial *material, ListBase *nodes, GPUOutput *output, bool use_new_shading) | ||||
| { | { | ||||
| DynStr *ds = BLI_dynstr_new(); | DynStr *ds = BLI_dynstr_new(); | ||||
| char *code; | char *code; | ||||
| int builtins; | int builtins; | ||||
| #ifdef WITH_OPENSUBDIV | #ifdef WITH_OPENSUBDIV | ||||
| GPUNode *node; | GPUNode *node; | ||||
| GPUInput *input; | GPUInput *input; | ||||
| #endif | #endif | ||||
| #if 0 | #if 0 | ||||
| BLI_dynstr_append(ds, FUNCTION_PROTOTYPES); | BLI_dynstr_append(ds, FUNCTION_PROTOTYPES); | ||||
| #endif | #endif | ||||
| codegen_set_unique_ids(nodes); | codegen_set_unique_ids(nodes); | ||||
| builtins = codegen_print_uniforms_functions(ds, nodes); | builtins = codegen_process_uniforms_functions(material, ds, nodes); | ||||
| #if 0 | #if 0 | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| BLI_dynstr_appendf(ds, "/* %s */\n", name); | BLI_dynstr_appendf(ds, "/* %s */\n", name); | ||||
| #endif | #endif | ||||
| BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); | BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); | ||||
| ▲ Show 20 Lines • Show All 677 Lines • ▼ Show 20 Lines | static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType type) | ||||
| GPUNode *outnode; | GPUNode *outnode; | ||||
| const char *name; | const char *name; | ||||
| if (link->output) { | if (link->output) { | ||||
| outnode = link->output->node; | outnode = link->output->node; | ||||
| name = outnode->name; | name = outnode->name; | ||||
| input = outnode->inputs.first; | input = outnode->inputs.first; | ||||
| if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) && | if ((STREQ(name, "set_value") || STREQ(name, "set_rgb") || STREQ(name, "set_rgba")) && | ||||
| (input->type == type)) | (input->type == type)) | ||||
| { | { | ||||
| input = MEM_dupallocN(outnode->inputs.first); | input = MEM_dupallocN(outnode->inputs.first); | ||||
| input->type = type; | input->type = type; | ||||
| if (input->link) | if (input->link) | ||||
| input->link->users++; | input->link->users++; | ||||
| BLI_addtail(&node->inputs, input); | BLI_addtail(&node->inputs, input); | ||||
| return; | return; | ||||
| ▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Lines | GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data) | ||||
| link->ptr2 = data; | link->ptr2 = data; | ||||
| link->dynamic = true; | link->dynamic = true; | ||||
| link->dynamictype = dynamictype; | link->dynamictype = dynamictype; | ||||
| return link; | return link; | ||||
| } | } | ||||
| /** | |||||
| * Add uniform to UBO struct of GPUMaterial. | |||||
| */ | |||||
| GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype) | |||||
| { | |||||
| GPUNodeLink *link = GPU_node_link_create(); | |||||
| link->ptr1 = num; | |||||
| link->ptr2 = NULL; | |||||
| link->dynamic = true; | |||||
| link->dynamictype = GPU_DYNAMIC_UBO; | |||||
| link->type = gputype; | |||||
| return link; | |||||
| } | |||||
| GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) | GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) | ||||
| { | { | ||||
| GPUNodeLink *link = GPU_node_link_create(); | GPUNodeLink *link = GPU_node_link_create(); | ||||
| link->image = GPU_NODE_LINK_IMAGE_BLENDER; | link->image = GPU_NODE_LINK_IMAGE_BLENDER; | ||||
| link->ptr1 = ima; | link->ptr1 = ima; | ||||
| link->ptr2 = iuser; | link->ptr2 = iuser; | ||||
| link->image_isdata = is_data; | link->image_isdata = is_data; | ||||
| ▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | if (link->output) { | ||||
| } | } | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| else | else | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** | |||||
| * When checking output nodes we can't rely on GPUNodeStack->link | |||||
| * So in this case we always link and leave to discard them later. | |||||
| */ | |||||
| static GPUNodeLink *gpu_uniformbuffer_link( | |||||
| GPUMaterial *mat, ListBase *sockets, GPUNodeStack *stack, GPUType gputype, const int index, const bool is_output) | |||||
| { | |||||
| if (is_output || (stack[index].link == NULL)) { | |||||
| bNodeSocket *socket = BLI_findlink(sockets, index); | |||||
| BLI_assert(socket != NULL); | |||||
| switch (gputype) { | |||||
fclemUnsubmitted Done Inline ActionsCan't we use bNodeSocket->type for this instead of passing the gputype and potentially have errors? fclem: Can't we use bNodeSocket->type for this instead of passing the gputype and potentially have… | |||||
| case GPU_FLOAT: | |||||
| { | |||||
| bNodeSocketValueFloat *sock = socket->default_value; | |||||
| GPUNodeLink *link = GPU_uniform_buffer(&sock->value, GPU_FLOAT); | |||||
| if (!is_output) { | |||||
| GPU_link(mat, "set_value", link, &stack[index].link); | |||||
| } | |||||
| return link; | |||||
| } | |||||
| case GPU_VEC3: | |||||
| { | |||||
| bNodeSocketValueRGBA *sock = socket->default_value; | |||||
| GPUNodeLink *link = GPU_uniform_buffer(sock->value, GPU_VEC3); | |||||
| if (!is_output) { | |||||
| GPU_link(mat, "set_rgb", link, &stack[index].link); | |||||
| } | |||||
| return link; | |||||
| } | |||||
| case GPU_VEC4: | |||||
| { | |||||
| bNodeSocketValueRGBA *sock = socket->default_value; | |||||
| GPUNodeLink *link = GPU_uniform_buffer(sock->value, GPU_VEC4); | |||||
| if (!is_output) { | |||||
| GPU_link(mat, "set_rgba", link, &stack[index].link); | |||||
| } | |||||
| return link; | |||||
| } | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, ListBase *sockets, GPUNodeStack *stack, GPUType gputype, const int index) | |||||
| { | |||||
| return gpu_uniformbuffer_link(mat, sockets, stack, gputype, index, true); | |||||
| } | |||||
| GPUNodeLink *GPU_uniformbuffer_link_in(GPUMaterial *mat, ListBase *sockets, GPUNodeStack *stack, GPUType gputype, const int index) | |||||
| { | |||||
| return gpu_uniformbuffer_link(mat, sockets, stack, gputype, index, false); | |||||
| } | |||||
| /* Pass create/free */ | /* Pass create/free */ | ||||
| static void gpu_nodes_tag(GPUNodeLink *link) | static void gpu_nodes_tag(GPUNodeLink *link) | ||||
| { | { | ||||
| GPUNode *node; | GPUNode *node; | ||||
| GPUInput *input; | GPUInput *input; | ||||
| if (!link->output) | if (!link->output) | ||||
| Show All 24 Lines | for (node = nodes->first; node; node = next) { | ||||
| if (!node->tag) { | if (!node->tag) { | ||||
| BLI_remlink(nodes, node); | BLI_remlink(nodes, node); | ||||
| gpu_node_free(node); | gpu_node_free(node); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| GPUPass *GPU_generate_pass_new( | GPUPass *GPU_generate_pass_new( | ||||
| struct GPUMaterial *material, | |||||
| ListBase *nodes, struct GPUNodeLink *frag_outlink, | ListBase *nodes, struct GPUNodeLink *frag_outlink, | ||||
| GPUVertexAttribs *attribs, | GPUVertexAttribs *attribs, | ||||
| const char *vert_code, const char *geom_code, | const char *vert_code, const char *geom_code, | ||||
| const char *frag_lib, const char *defines) | const char *frag_lib, const char *defines) | ||||
| { | { | ||||
| GPUShader *shader; | GPUShader *shader; | ||||
| GPUPass *pass; | GPUPass *pass; | ||||
| char *vertexgen, *fragmentgen, *tmp; | char *vertexgen, *fragmentgen, *tmp; | ||||
| char *vertexcode, *geometrycode, *fragmentcode; | char *vertexcode, *geometrycode, *fragmentcode; | ||||
| /* prune unused nodes */ | /* prune unused nodes */ | ||||
| gpu_nodes_prune(nodes, frag_outlink); | gpu_nodes_prune(nodes, frag_outlink); | ||||
| gpu_nodes_get_vertex_attributes(nodes, attribs); | gpu_nodes_get_vertex_attributes(nodes, attribs); | ||||
| /* generate code and compile with opengl */ | /* generate code and compile with opengl */ | ||||
| fragmentgen = code_generate_fragment(nodes, frag_outlink->output, true); | fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true); | ||||
| vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL)); | vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL)); | ||||
| tmp = BLI_strdupcat(frag_lib, glsl_material_library); | tmp = BLI_strdupcat(frag_lib, glsl_material_library); | ||||
| fragmentcode = BLI_strdupcat(tmp, fragmentgen); | fragmentcode = BLI_strdupcat(tmp, fragmentgen); | ||||
| vertexcode = BLI_strdup(vertexgen); | vertexcode = BLI_strdup(vertexgen); | ||||
| if (geom_code) { | if (geom_code) { | ||||
| geometrycode = code_generate_geometry_new(nodes, geom_code); | geometrycode = code_generate_geometry_new(nodes, geom_code); | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | #endif | ||||
| /* prune unused nodes */ | /* prune unused nodes */ | ||||
| gpu_nodes_prune(nodes, outlink); | gpu_nodes_prune(nodes, outlink); | ||||
| gpu_nodes_get_vertex_attributes(nodes, attribs); | gpu_nodes_get_vertex_attributes(nodes, attribs); | ||||
| gpu_nodes_get_builtin_flag(nodes, builtins); | gpu_nodes_get_builtin_flag(nodes, builtins); | ||||
| /* generate code and compile with opengl */ | /* generate code and compile with opengl */ | ||||
| fragmentcode = code_generate_fragment(nodes, outlink->output, false); | fragmentcode = code_generate_fragment(NULL, nodes, outlink->output, false); | ||||
| vertexcode = code_generate_vertex(nodes, type); | vertexcode = code_generate_vertex(nodes, type); | ||||
| geometrycode = code_generate_geometry(nodes, use_opensubdiv); | geometrycode = code_generate_geometry(nodes, use_opensubdiv); | ||||
| int flags = GPU_SHADER_FLAGS_NONE; | int flags = GPU_SHADER_FLAGS_NONE; | ||||
| if (use_opensubdiv) { | if (use_opensubdiv) { | ||||
| flags |= GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV; | flags |= GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV; | ||||
| } | } | ||||
| if (use_new_shading) { | if (use_new_shading) { | ||||
| ▲ Show 20 Lines • Show All 55 Lines • Show Last 20 Lines | |||||
You don't need the uniform identifier here.