diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-04-27 23:27:09 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-05-01 19:11:21 +0300 |
commit | e868b459bb8efc35012b2364762f3d25d96b8b0d (patch) | |
tree | eb2c0e9909a3a4ea5225f6b537f8b7fbdf51d832 /source/blender/gpu/intern | |
parent | 2f100c13ee14cc6876423d1ac39ef9c565fb8987 (diff) |
Eevee: World nodetree gpumaterial compatibility.
- Unify GPUMaterial creation (world/mesh).
- Support for multiple shader variations (not used for now).
- Convert GPUInputs to DRWUniforms to be used with the draw manager.
- Nodetree Update is not supported. The only way to refresh the shaders is to change render engine.
- Cleanup in GPUPass.
- Add new temporary Node Compatibility type. Compatibility types should be removed in the future.
Diffstat (limited to 'source/blender/gpu/intern')
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.c | 123 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.h | 6 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_material.c | 56 |
3 files changed, 179 insertions, 6 deletions
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index de2b94482f4..89c58eb8495 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -928,6 +928,67 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } +static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes) +{ + GPUShader *shader = pass->shader; + GPUNode *node; + GPUInput *next, *input; + ListBase *inputs = &pass->inputs; + int extract, z; + + memset(inputs, 0, sizeof(*inputs)); + + if (!shader) + return; + + GPU_shader_bind(shader); + + for (node = nodes->first; node; node = node->next) { + z = 0; + for (input = node->inputs.first; input; input = next, z++) { + next = input->next; + + /* attributes don't need to be bound, they already have + * an id that the drawing functions will use */ + if (input->source == GPU_SOURCE_ATTRIB) { + continue; + } + + if (input->source == GPU_SOURCE_BUILTIN || + input->source == GPU_SOURCE_OPENGL_BUILTIN) + { + continue; + } + + if (input->ima || input->tex || input->prv) + BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); + else + BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); + + /* pass non-dynamic uniforms to opengl */ + extract = 0; + + if (input->ima || input->tex || input->prv) { + if (input->bindtex) + extract = 1; + } + else if (input->dynamicvec) + extract = 1; + + if (extract) + input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); + + /* extract nodes */ + if (extract) { + BLI_remlink(&node->inputs, input); + BLI_addtail(inputs, input); + } + } + } + + GPU_shader_unbind(); +} + static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) { GPUShader *shader = pass->shader; @@ -1647,6 +1708,67 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } +GPUPass *GPU_generate_pass_new(ListBase *nodes, struct GPUNodeLink *frag_outlink, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines) +{ + GPUShader *shader; + GPUPass *pass; + char *vertexgen, *geometrygen, *fragmentgen, *tmp; + char *vertexcode, *geometrycode, *fragmentcode; + + /* prune unused nodes */ + gpu_nodes_prune(nodes, frag_outlink); + + /* generate code and compile with opengl */ + fragmentgen = code_generate_fragment(nodes, frag_outlink->output); + // vertexgen = code_generate_vertex(nodes, GPU_MATERIAL_TYPE_MESH); + // geometrygen = code_generate_geometry(nodes, false); + UNUSED_VARS(vertexgen, geometrygen); + + tmp = BLI_strdupcat(frag_lib, glsl_material_library); + fragmentcode = BLI_strdupcat(tmp, fragmentgen); + vertexcode = BLI_strdup(vert_code); + geometrycode = BLI_strdup(geom_code); + + shader = GPU_shader_create(vertexcode, + fragmentcode, + geometrycode, + NULL, + defines); + + MEM_freeN(tmp); + + /* failed? */ + if (!shader) { + if (fragmentcode) + MEM_freeN(fragmentcode); + if (vertexcode) + MEM_freeN(vertexcode); + if (geometrycode) + MEM_freeN(geometrycode); + MEM_freeN(fragmentgen); + gpu_nodes_free(nodes); + return NULL; + } + + /* create pass */ + pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = shader; + pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; + pass->vertexcode = vertexcode; + pass->libcode = glsl_material_library; + + /* extract dynamic inputs and throw away nodes */ + gpu_nodes_extract_dynamic_inputs_new(pass, nodes); + gpu_nodes_free(nodes); + + MEM_freeN(fragmentgen); + + return pass; +} + GPUPass *GPU_generate_pass( ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, @@ -1705,7 +1827,6 @@ GPUPass *GPU_generate_pass( /* create pass */ pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->output = outlink->output; pass->shader = shader; pass->fragmentcode = fragmentcode; pass->geometrycode = geometrycode; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 7af17f9122d..9263fe3bc3f 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -156,10 +156,7 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { - struct GPUPass *next, *prev; - ListBase inputs; - struct GPUOutput *output; struct GPUShader *shader; char *fragmentcode; char *geometrycode; @@ -170,6 +167,9 @@ struct GPUPass { typedef struct GPUPass GPUPass; +GPUPass *GPU_generate_pass_new(ListBase *nodes, struct GPUNodeLink *frag_outlink, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines); GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink, struct GPUVertexAttribs *attribs, int *builtin, const GPUMatType type, const char *name, diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index aa7a104ff86..083b0596b1c 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -94,12 +94,15 @@ static struct GPUWorld { } GPUWorld; struct GPUMaterial { - Scene *scene; + Scene *scene; /* DEPRECATED was only usefull for lamps */ Material *ma; /* material for mesh surface, worlds or something else. * some code generation is done differently depending on the use case */ - int type; + int type; /* DEPRECATED */ + + void *engine; /* attached engine type */ + int options; /* to identify shader variations (shadow, probe, world background...) */ /* for creating the material */ ListBase nodes; @@ -436,6 +439,10 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material) return material->type; } +GPUPass *GPU_material_get_pass(GPUMaterial *material) +{ + return material->pass; +} void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { @@ -470,6 +477,10 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node) bool GPU_material_do_color_management(GPUMaterial *mat) { + /* XXX mat->scene == NULL in that case */ + if (mat->engine) + return true; + if (!BKE_scene_check_color_management_enabled(mat->scene)) return false; @@ -2096,6 +2107,47 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) return mat; } +/* TODO : This is supposed to replace GPU_material_from_blender/_world in the future */ +GPUMaterial *GPU_material_from_nodetree( + struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat; + GPUNodeLink *outlink; + LinkData *link; + + for (link = gpumaterials->first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial *)link->data; + if (current_material->engine == engine_type && + current_material->options == options) + { + return current_material; + } + } + + /* allocate material */ + mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */ + mat->engine = engine_type; + mat->options = options; + + ntreeGPUMaterialNodes(ntree, mat, NODE_NEWER_SHADING); + + /* Let Draw manager finish the construction. */ + if (mat->outlink) { + outlink = mat->outlink; + mat->pass = GPU_generate_pass_new(&mat->nodes, outlink, vert_code, geom_code, frag_lib, defines); + } + + /* note that even if building the shader fails in some way, we still keep + * it to avoid trying to compile again and again, and simple do not use + * the actual shader on drawing */ + + link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + link->data = mat; + BLI_addtail(gpumaterials, link); + + return mat; +} GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) { |