From 3a209c285754a08339c654d075b5d273fa264c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 5 Mar 2018 00:54:31 +0100 Subject: DRW: Deferred compilation initial implementation. --- source/blender/draw/DRW_engine.h | 3 + .../blender/draw/engines/eevee/eevee_materials.c | 53 +++--- source/blender/draw/intern/DRW_render.h | 6 + source/blender/draw/intern/draw_manager.c | 2 + source/blender/draw/intern/draw_manager.h | 3 + source/blender/draw/intern/draw_manager_shader.c | 192 +++++++++++++++++++++ source/blender/gpu/GPU_material.h | 10 +- source/blender/gpu/intern/gpu_codegen.c | 13 +- source/blender/gpu/intern/gpu_codegen.h | 3 + source/blender/gpu/intern/gpu_material.c | 51 +++++- 10 files changed, 296 insertions(+), 40 deletions(-) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 4043f39b46d..cc4c0ed10e8 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -46,6 +46,7 @@ struct ViewContext; struct ViewportEngineData; struct View3D; struct rcti; +struct GPUMaterial; struct GPUOffScreen; struct GPUViewport; struct RenderEngine; @@ -136,4 +137,6 @@ void DRW_opengl_context_destroy(void); void DRW_opengl_context_enable(void); void DRW_opengl_context_disable(void); +void DRW_deferred_shader_remove(struct GPUMaterial *mat); + #endif /* __DRW_ENGINE_H__ */ diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 31ef26a1e9e..1cf49d7166c 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -630,8 +630,8 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor if (mat != NULL) { return mat; } - return GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine, options, + return DRW_shader_create_from_world( + scene, wo, engine, options, datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib, SHADER_DEFINES "#define PROBE_CAPTURE\n"); } @@ -645,8 +645,8 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor if (mat != NULL) { return mat; } - return GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine, options, + return DRW_shader_create_from_world( + scene, wo, engine, options, datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib, SHADER_DEFINES "#define WORLD_BACKGROUND\n"); } @@ -663,8 +663,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * char *defines = eevee_get_volume_defines(options); - mat = GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine, options, + mat = DRW_shader_create_from_world( + scene, wo, engine, options, datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib, defines); @@ -698,8 +698,8 @@ struct GPUMaterial *EEVEE_material_mesh_get( char *defines = eevee_get_defines(options); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib, defines); @@ -720,8 +720,8 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material char *defines = eevee_get_volume_defines(options); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib, defines); @@ -758,8 +758,8 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, (is_shadow) ? datatoc_shadow_vert_glsl : datatoc_lit_surface_vert_glsl, (is_shadow) ? datatoc_shadow_geom_glsl : NULL, frag_str, @@ -786,8 +786,8 @@ struct GPUMaterial *EEVEE_material_hair_get( char *defines = eevee_get_defines(options); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib, defines); @@ -883,17 +883,24 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) col = &wo->horr; if (wo->use_nodes && wo->nodetree) { + static float error_col[3] = {1.0f, 0.0f, 1.0f}; + static float compile_col[3] = {0.5f, 0.5f, 0.5f}; struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - grp = DRW_shgroup_material_create(gpumat, psl->background_pass); - if (grp) { - DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - DRW_shgroup_call_add(grp, geom, NULL); - } - else { - /* Shader failed : pink background */ - static float pink[3] = {1.0f, 0.0f, 1.0f}; - col = pink; + switch (GPU_material_status(gpumat)) { + case GPU_MAT_SUCCESS: + grp = DRW_shgroup_material_create(gpumat, psl->background_pass); + DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + DRW_shgroup_call_add(grp, geom, NULL); + break; + case GPU_MAT_QUEUED: + /* TODO Bypass probe compilation. */ + col = compile_col; + break; + case GPU_MAT_FAILED: + default: + col = error_col; + break; } } } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index d8885bd77c5..4815c117a8c 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -268,6 +268,12 @@ struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_3D_depth_only(void); +struct GPUMaterial *DRW_shader_create_from_world( + struct Scene *scene, struct World *wo, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines); +struct GPUMaterial *DRW_shader_create_from_material( + struct Scene *scene, struct Material *ma, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines); void DRW_shader_free(struct GPUShader *shader); #define DRW_SHADER_FREE_SAFE(shader) do { \ if (shader != NULL) { \ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 8feffa246ef..ac39bbf132a 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1957,6 +1957,7 @@ void DRW_opengl_context_create(void) immDeactivate(); /* This changes the active context. */ + DRW_deferred_compiler_init(); DST.ogl_context = WM_opengl_context_create(); /* Be sure to create gawain.context too. */ DST.gwn_context = GWN_context_create(); @@ -1971,6 +1972,7 @@ void DRW_opengl_context_destroy(void) { BLI_assert(BLI_thread_is_main()); if (DST.ogl_context != NULL) { + DRW_deferred_compiler_exit(); WM_opengl_context_activate(DST.ogl_context); GWN_context_active_set(DST.gwn_context); GWN_context_discard(DST.gwn_context); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index f8989a0703a..3c6682050cf 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -356,4 +356,7 @@ void *drw_viewport_engine_data_ensure(void *engine_type); void drw_state_set(DRWState state); +void DRW_deferred_compiler_init(void); +void DRW_deferred_compiler_exit(void); + #endif /* __DRAW_MANAGER_H__ */ diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index e9d2ac14e57..27605012993 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -25,15 +25,181 @@ #include "draw_manager.h" +#include "DNA_world_types.h" +#include "DNA_material_types.h" + +#include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_utils.h" +#include "BLI_threads.h" +#include "BLI_task.h" #include "GPU_shader.h" +#include "GPU_material.h" + +#include "WM_api.h" extern char datatoc_gpu_shader_2D_vert_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; + +/* -------------------------------------------------------------------- */ + +/** \name Deferred Compilation (DRW_deferred) + * + * Since compiling shader can take a long time, we do it in a non blocking + * manner in another thread. + * + * \{ */ + +typedef struct DRWDeferredShader { + struct DRWDeferredShader *prev, *next; + + GPUMaterial *mat; + char *vert, *geom, *frag, *defs; + + ThreadMutex compilation_mutex; +} DRWDeferredShader; + +typedef struct DRWShaderCompiler { + ListBase queue; /* DRWDeferredShader */ + ThreadMutex list_mutex; + + DRWDeferredShader *mat_compiling; + ThreadMutex compilation_mutex; + + TaskScheduler *task_scheduler; /* NULL if nothing is running. */ + TaskPool *task_pool; + + void *ogl_context; +} DRWShaderCompiler; + +static DRWShaderCompiler DSC = {{NULL}}; + +static void drw_deferred_shader_free(DRWDeferredShader *dsh) +{ + /* Make sure it is not queued before freeing. */ + BLI_assert(BLI_findindex(&DSC.queue, dsh) == -1); + + MEM_SAFE_FREE(dsh->vert); + MEM_SAFE_FREE(dsh->geom); + MEM_SAFE_FREE(dsh->frag); + MEM_SAFE_FREE(dsh->defs); + + MEM_freeN(dsh); +} + +static void drw_deferred_shader_compilation_exec(TaskPool * __restrict UNUSED(pool), void *UNUSED(taskdata), int UNUSED(threadid)) +{ + WM_opengl_context_activate(DSC.ogl_context); + + while (true) { + BLI_mutex_lock(&DSC.list_mutex); + DSC.mat_compiling = BLI_pophead(&DSC.queue); + if (DSC.mat_compiling == NULL) { + break; + } + BLI_mutex_lock(&DSC.compilation_mutex); + BLI_mutex_unlock(&DSC.list_mutex); + + /* Do the compilation. */ + GPU_material_generate_pass( + DSC.mat_compiling->mat, + DSC.mat_compiling->vert, + DSC.mat_compiling->geom, + DSC.mat_compiling->frag, + DSC.mat_compiling->defs); + + BLI_mutex_unlock(&DSC.compilation_mutex); + + drw_deferred_shader_free(DSC.mat_compiling); + } + + WM_opengl_context_release(DSC.ogl_context); + BLI_mutex_unlock(&DSC.list_mutex); +} + +static void drw_deferred_shader_add( + GPUMaterial *mat, const char *vert, const char *geom, const char *frag_lib, const char *defines) +{ + if (DRW_state_is_image_render()) { + /* Do not deferre the compilation if we are rendering for image. */ + GPU_material_generate_pass(mat, vert, geom, frag_lib, defines); + return; + } + + DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader"); + + dsh->mat = mat; + if (vert) dsh->vert = BLI_strdup(vert); + if (geom) dsh->geom = BLI_strdup(geom); + if (frag_lib) dsh->frag = BLI_strdup(frag_lib); + if (defines) dsh->defs = BLI_strdup(defines); + + BLI_mutex_lock(&DSC.list_mutex); + BLI_addtail(&DSC.queue, dsh); + if (DSC.mat_compiling == NULL) { + /* Set value so that other threads do not start a new task. */ + DSC.mat_compiling = (void *)1; + + if (DSC.task_scheduler == NULL) { + DSC.task_scheduler = BLI_task_scheduler_create(1); + DSC.task_pool = BLI_task_pool_create_background(DSC.task_scheduler, NULL); + } + BLI_task_pool_push(DSC.task_pool, drw_deferred_shader_compilation_exec, NULL, false, TASK_PRIORITY_LOW); + } + BLI_mutex_unlock(&DSC.list_mutex); +} + +void DRW_deferred_shader_remove(GPUMaterial *mat) +{ + BLI_mutex_lock(&DSC.list_mutex); + DRWDeferredShader *dsh = (DRWDeferredShader *)BLI_findptr(&DSC.queue, mat, offsetof(DRWDeferredShader, mat)); + if (dsh) { + BLI_remlink(&DSC.queue, dsh); + } + if (DSC.mat_compiling != NULL) { + if (DSC.mat_compiling->mat == mat) { + /* Wait for compilation to finish */ + BLI_mutex_lock(&DSC.compilation_mutex); + BLI_mutex_unlock(&DSC.compilation_mutex); + } + } + BLI_mutex_unlock(&DSC.list_mutex); + if (dsh) { + drw_deferred_shader_free(dsh); + } +} + + +static void drw_deferred_compiler_finish(void) +{ + if (DSC.task_scheduler != NULL) { + BLI_task_pool_work_and_wait(DSC.task_pool); + BLI_task_pool_free(DSC.task_pool); + BLI_task_scheduler_free(DSC.task_scheduler); + DSC.task_scheduler = NULL; + } +} + +void DRW_deferred_compiler_init(void) +{ + BLI_mutex_init(&DSC.list_mutex); + BLI_mutex_init(&DSC.compilation_mutex); + DSC.ogl_context = WM_opengl_context_create(); +} + +void DRW_deferred_compiler_exit(void) +{ + drw_deferred_compiler_finish(); + WM_opengl_context_dispose(DSC.ogl_context); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines) { return GPU_shader_create(vert, frag, geom, NULL, defines); @@ -84,6 +250,32 @@ GPUShader *DRW_shader_create_3D_depth_only(void) return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); } +GPUMaterial *DRW_shader_create_from_world( + struct Scene *scene, World *wo, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat = GPU_material_from_nodetree( + scene, wo->nodetree, &wo->gpumaterial, engine_type, options, + vert, geom, frag_lib, defines, true); + + drw_deferred_shader_add(mat, vert, geom, frag_lib, defines); + + return mat; +} + +GPUMaterial *DRW_shader_create_from_material( + struct Scene *scene, Material *ma, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat = GPU_material_from_nodetree( + scene, ma->nodetree, &ma->gpumaterial, engine_type, options, + vert, geom, frag_lib, defines, true); + + drw_deferred_shader_add(mat, vert, geom, frag_lib, defines); + + return mat; +} + void DRW_shader_free(GPUShader *shader) { GPU_shader_free(shader); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index b486ff14dd1..14c2043ebad 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -144,6 +144,11 @@ typedef struct GPUNodeStack { bool end; } GPUNodeStack; +typedef enum GPUMaterialSatus { + GPU_MAT_FAILED = 0, + GPU_MAT_QUEUED, + GPU_MAT_SUCCESS, +} GPUMaterialSatus; #define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000) @@ -245,9 +250,11 @@ GPUMaterial *GPU_material_from_nodetree_find( struct ListBase *gpumaterials, const void *engine_type, int options); GPUMaterial *GPU_material_from_nodetree( struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options, - const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, bool deferred); GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv); GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv); +void GPU_material_generate_pass( + GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(void); @@ -263,6 +270,7 @@ bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); GPUMatType GPU_Material_get_type(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); +GPUMaterialSatus GPU_material_status(GPUMaterial *mat); struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material); void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index ece78d4a5cf..b6f92497063 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1720,7 +1720,7 @@ static void gpu_nodes_free(ListBase *nodes) /* vertex attributes */ -static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs) +void GPU_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs) { GPUNode *node; GPUInput *input; @@ -2052,7 +2052,7 @@ static void gpu_nodes_tag(GPUNodeLink *link) gpu_nodes_tag(input->link); } -static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) +void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) { GPUNode *node, *next; @@ -2084,9 +2084,9 @@ GPUPass *GPU_generate_pass_new( char *vertexcode, *geometrycode, *fragmentcode; /* 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 */ fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true); @@ -2135,7 +2135,6 @@ GPUPass *GPU_generate_pass_new( /* extract dynamic inputs and throw away nodes */ gpu_nodes_extract_dynamic_inputs_new(pass, nodes); - gpu_nodes_free(nodes); MEM_freeN(fragmentgen); MEM_freeN(vertexgen); @@ -2162,9 +2161,9 @@ GPUPass *GPU_generate_pass( #endif /* 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); /* generate code and compile with opengl */ diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 14e07a6e012..0f8218c9c15 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -183,6 +183,9 @@ GPUPass *GPU_generate_pass( struct GPUShader *GPU_pass_shader(GPUPass *pass); +void GPU_nodes_get_vertex_attributes(ListBase *nodes, struct GPUVertexAttribs *attribs); +void GPU_nodes_prune(ListBase *nodes, struct GPUNodeLink *outlink); + void GPU_pass_bind(GPUPass *pass, double time, int mipmap); void GPU_pass_update_uniforms(GPUPass *pass); void GPU_pass_unbind(GPUPass *pass); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 2d7b9415030..4d888824f97 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -68,6 +68,8 @@ #include "GPU_texture.h" #include "GPU_uniformbuffer.h" +#include "DRW_engine.h" + #include "gpu_codegen.h" #include "gpu_lamp_private.h" @@ -103,6 +105,7 @@ struct GPUMaterial { /* material for mesh surface, worlds or something else. * some code generation is done differently depending on the use case */ int type; /* DEPRECATED */ + GPUMaterialSatus status; const void *engine_type; /* attached engine type */ int options; /* to identify shader variations (shadow, probe, world background...) */ @@ -142,7 +145,10 @@ struct GPUMaterial { */ int domain; + /* Used by 2.8 pipeline */ GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ + + /* Eevee SSS */ GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ float *sss_radii; /* UBO containing SSS profile. */ @@ -221,6 +227,8 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam material->is_opensubdiv, GPU_material_use_new_shading_nodes(material)); + material->status = (material->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED; + if (!material->pass) return 0; @@ -270,6 +278,11 @@ void GPU_material_free(ListBase *gpumaterial) for (LinkData *link = gpumaterial->first; link; link = link->next) { GPUMaterial *material = link->data; + /* Cancel / wait any pending lazy compilation. */ + DRW_deferred_shader_remove(material); + + GPU_pass_free_nodes(&material->nodes); + if (material->pass) GPU_pass_free(material->pass); @@ -829,6 +842,12 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node) BLI_addtail(&material->nodes, node); } +/* Return true if the material compilation has not yet begin or begin. */ +GPUMaterialSatus GPU_material_status(GPUMaterial *mat) +{ + return mat->status; +} + /* Code generation */ bool GPU_material_do_color_management(GPUMaterial *mat) @@ -2490,10 +2509,8 @@ GPUMaterial *GPU_material_from_nodetree_find( */ GPUMaterial *GPU_material_from_nodetree( Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options, - const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, bool deferred) { - GPUMaterial *mat; - GPUNodeLink *outlink; LinkData *link; bool has_volume_output, has_surface_output; @@ -2501,7 +2518,7 @@ GPUMaterial *GPU_material_from_nodetree( BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); /* allocate material */ - mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */ + GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");; mat->scene = scene; mat->engine_type = engine_type; mat->options = options; @@ -2516,11 +2533,15 @@ GPUMaterial *GPU_material_from_nodetree( mat->domain |= GPU_DOMAIN_VOLUME; } - /* Let Draw manager finish the construction. */ - if (mat->outlink) { - outlink = mat->outlink; - mat->pass = GPU_generate_pass_new( - mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines); + if (!deferred) { + GPU_material_generate_pass(mat, vert_code, geom_code, frag_lib, defines); + } + else if (mat->outlink) { + /* Prune the unused nodes and extract attribs before compiling so the + * generated VBOs are ready to accept the future shader. */ + GPU_nodes_prune(&mat->nodes, mat->outlink); + GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs); + mat->status = GPU_MAT_QUEUED; } /* note that even if building the shader fails in some way, we still keep @@ -2534,6 +2555,18 @@ GPUMaterial *GPU_material_from_nodetree( return mat; } +/* Calls this function if /a mat was created with deferred compilation. */ +void GPU_material_generate_pass( + GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +{ + BLI_assert(mat->pass == NULL); /* Only run once! */ + if (mat->outlink) { + mat->pass = GPU_generate_pass_new( + mat, &mat->nodes, mat->outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines); + mat->status = (mat->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED; + } +} + GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) { GPUMaterial *mat; -- cgit v1.2.3