Commit: 765d7242d5a14551d0dc876f13bf6ee579b47b10
Author: Clément Foucault
Date:   Sun Mar 11 23:43:09 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB765d7242d5a14551d0dc876f13bf6ee579b47b10

GPUMaterial: Add Material shader cache.

This is mostly to avoid re-compilation when using undo/redo operators.
This also has the benefit to reuse the same GPUShader for multiple materials 
using the same nodetree configuration.

The cache stores GPUPasses that already contains the shader code and a hash to 
test for matches.
We use refcounts to know when a GPUPass is not used anymore.

I had to move the GPUInput list from GPUPass to GPUMaterial because it's 
containing references to the material nodetree and cannot be reused.

A garbage collection is hardcoded to run every 60 seconds to free every unused 
GPUPass.

===================================================================

M       source/blender/draw/intern/draw_manager_data.c
M       source/blender/editors/space_view3d/view3d_draw.c
M       source/blender/gpu/GPU_material.h
M       source/blender/gpu/intern/gpu_codegen.c
M       source/blender/gpu/intern/gpu_codegen.h
M       source/blender/gpu/intern/gpu_material.c
M       source/blender/windowmanager/intern/wm_init_exit.c

===================================================================

diff --git a/source/blender/draw/intern/draw_manager_data.c 
b/source/blender/draw/intern/draw_manager_data.c
index 09ed1443701..4648c321f26 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -582,15 +582,14 @@ static DRWShadingGroup 
*drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass
        return grp;
 }
 
-static DRWShadingGroup *drw_shgroup_material_inputs(
-         DRWShadingGroup *grp, struct GPUMaterial *material, GPUPass *gpupass)
+static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, 
struct GPUMaterial *material)
 {
        /* TODO : Ideally we should not convert. But since the whole codegen
         * is relying on GPUPass we keep it as is for now. */
 
-       /* Converting dynamic GPUInput to DRWUniform */
-       ListBase *inputs = &gpupass->inputs;
+       ListBase *inputs = GPU_material_get_inputs(material);
 
+       /* Converting dynamic GPUInput to DRWUniform */
        for (GPUInput *input = inputs->first; input; input = input->next) {
                /* Textures */
                if (input->ima) {
@@ -656,7 +655,7 @@ DRWShadingGroup *DRW_shgroup_material_create(
 
        if (shgroup) {
                drw_interface_init(shgroup, GPU_pass_shader(gpupass));
-               drw_shgroup_material_inputs(shgroup, material, gpupass);
+               drw_shgroup_material_inputs(shgroup, material);
        }
 
        return shgroup;
@@ -673,7 +672,7 @@ DRWShadingGroup *DRW_shgroup_material_instance_create(
                shgroup->instance_geom = geom;
                drw_call_calc_orco(ob->data, shgroup->instance_orcofac);
                drw_interface_instance_init(shgroup, GPU_pass_shader(gpupass), 
geom, format);
-               drw_shgroup_material_inputs(shgroup, material, gpupass);
+               drw_shgroup_material_inputs(shgroup, material);
        }
 
        return shgroup;
@@ -693,7 +692,7 @@ DRWShadingGroup 
*DRW_shgroup_material_empty_tri_batch_create(
                drw_interface_init(shgroup, GPU_pass_shader(gpupass));
                shgroup->type = DRW_SHG_TRIANGLE_BATCH;
                shgroup->instance_count = tri_count * 3;
-               drw_shgroup_material_inputs(shgroup, material, gpupass);
+               drw_shgroup_material_inputs(shgroup, material);
        }
 
        return shgroup;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c 
b/source/blender/editors/space_view3d/view3d_draw.c
index 02d45be5aa4..4fa2eee8956 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1922,6 +1922,8 @@ void view3d_main_region_draw(const bContext *C, ARegion 
*ar)
        BLI_rcti_translate(&rect, -ar->winrct.xmin, -ar->winrct.ymin);
        GPU_viewport_draw_to_screen(rv3d->viewport, &rect);
 
+       GPU_pass_cache_garbage_collect();
+
        v3d->flag |= V3D_INVALID_BACKBUF;
 }
 
diff --git a/source/blender/gpu/GPU_material.h 
b/source/blender/gpu/GPU_material.h
index 6df465ac753..1d2b234e7f3 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -270,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);
+struct ListBase *GPU_material_get_inputs(GPUMaterial *material);
 GPUMaterialStatus GPU_material_status(GPUMaterial *mat);
 
 struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial 
*material);
@@ -377,6 +378,9 @@ void GPU_material_update_fvar_offset(GPUMaterial 
*gpu_material,
                                      struct DerivedMesh *dm);
 #endif
 
+void GPU_pass_cache_garbage_collect(void);
+void GPU_pass_cache_free(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/gpu/intern/gpu_codegen.c 
b/source/blender/gpu/intern/gpu_codegen.c
index b6f92497063..7cd403d2721 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -39,10 +39,14 @@
 #include "DNA_node_types.h"
 
 #include "BLI_blenlib.h"
+#include "BLI_hash_mm2a.h"
+#include "BLI_linklist.h"
 #include "BLI_utildefines.h"
 #include "BLI_dynstr.h"
 #include "BLI_ghash.h"
 
+#include "PIL_time.h"
+
 #include "GPU_extensions.h"
 #include "GPU_glew.h"
 #include "GPU_material.h"
@@ -64,6 +68,50 @@ extern char datatoc_gpu_shader_geometry_glsl[];
 
 static char *glsl_material_library = NULL;
 
+/* -------------------- GPUPass Cache ------------------ */
+/**
+ * Internal shader cache: This prevent the shader recompilation / stall when
+ * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
+ * same for 2 different Materials. Unused GPUPasses are free by Garbage 
collection.
+ **/
+
+static LinkNode *pass_cache = NULL; /* GPUPass */
+
+static uint32_t gpu_pass_hash(const char *vert, const char *geom, const char 
*frag, const char *defs)
+{
+       BLI_HashMurmur2A hm2a;
+       BLI_hash_mm2a_init(&hm2a, 0);
+       BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag, strlen(frag));
+       BLI_hash_mm2a_add(&hm2a, (unsigned char *)vert, strlen(vert));
+       if (defs)
+               BLI_hash_mm2a_add(&hm2a, (unsigned char *)defs, strlen(defs));
+       if (geom)
+               BLI_hash_mm2a_add(&hm2a, (unsigned char *)geom, strlen(geom));
+
+       return BLI_hash_mm2a_end(&hm2a);
+}
+
+/* Search by hash then by exact string match. */
+static GPUPass *gpu_pass_cache_lookup(
+        const char *vert, const char *geom, const char *frag, const char 
*defs, uint32_t hash)
+{
+       for (LinkNode *ln = pass_cache; ln; ln = ln->next) {
+               GPUPass *pass = (GPUPass *)ln->link;
+               if (pass->hash == hash) {
+                       /* Note: Could be made faster if that becomes a real 
bottleneck. */
+                       if ((defs != NULL) && (strcmp(pass->defines, defs) != 
0)) { /* Pass */ }
+                       else if ((geom != NULL) && (strcmp(pass->geometrycode, 
geom) != 0)) { /* Pass */ }
+                       else if ((strcmp(pass->fragmentcode, frag) == 0) &&
+                                (strcmp(pass->vertexcode, vert) == 0))
+                       {
+                               return pass;
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* -------------------- GPU Codegen ------------------ */
 
 /* type definitions and constants */
 
@@ -1175,15 +1223,13 @@ GPUShader *GPU_pass_shader(GPUPass *pass)
        return pass->shader;
 }
 
-static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase 
*nodes)
+static void gpu_nodes_extract_dynamic_inputs_new(GPUShader *shader, ListBase 
*inputs, ListBase *nodes)
 {
-       GPUShader *shader = pass->shader;
        GPUNode *node;
        GPUInput *next, *input;
-       ListBase *inputs = &pass->inputs;
        int extract, z;
 
-       memset(inputs, 0, sizeof(*inputs));
+       BLI_listbase_clear(inputs);
 
        if (!shader)
                return;
@@ -1236,15 +1282,13 @@ static void 
gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes)
        GPU_shader_unbind();
 }
 
-static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
+static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase 
*inputs, ListBase *nodes)
 {
-       GPUShader *shader = pass->shader;
        GPUNode *node;
        GPUInput *next, *input;
-       ListBase *inputs = &pass->inputs;
        int extract, z;
 
-       memset(inputs, 0, sizeof(*inputs));
+       BLI_listbase_clear(inputs);
 
        if (!shader)
                return;
@@ -1322,11 +1366,10 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass 
*pass, ListBase *nodes)
        GPU_shader_unbind();
 }
 
-void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
+void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap)
 {
        GPUInput *input;
        GPUShader *shader = pass->shader;
-       ListBase *inputs = &pass->inputs;
 
        if (!shader)
                return;
@@ -1351,11 +1394,10 @@ void GPU_pass_bind(GPUPass *pass, double time, int 
mipmap)
        }
 }
 
-void GPU_pass_update_uniforms(GPUPass *pass)
+void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs)
 {
        GPUInput *input;
        GPUShader *shader = pass->shader;
-       ListBase *inputs = &pass->inputs;
 
        if (!shader)
                return;
@@ -1376,11 +1418,10 @@ void GPU_pass_update_uniforms(GPUPass *pass)
        }
 }
 
-void GPU_pass_unbind(GPUPass *pass)
+void GPU_pass_unbind(GPUPass *pass, ListBase *inputs)
 {
        GPUInput *input;
        GPUShader *shader = pass->shader;
-       ListBase *inputs = &pass->inputs;
 
        if (!shader)
                return;
@@ -1679,7 +1720,7 @@ static void gpu_node_output(GPUNode *node, const GPUType 
type, GPUNodeLink **lin
        BLI_addtail(&node->outputs, output);
 }
 
-static void gpu_inputs_free(ListBase *inputs)
+void GPU_inputs_free(ListBase *inputs)
 {
        GPUInput *input;
 
@@ -1697,7 +1738,7 @@ static void gpu_node_free(GPUNode *node)
 {
        GPUOutput *output;
 
-       gpu_inputs_free(&node->inputs);
+       GPU_inputs_free(&node->inputs);
 
        for (output = node->outputs.first; output; output = output->next)
                if (output->link) {
@@ -2072,78 +2113,83 @@ void GPU_nodes_prune(ListBase *nodes, GPUNodeLink 
*outlink)
 }
 
 GPUPass *GPU_generate_pass_new(
-        struct GPUMaterial *material,
-        ListBase *nodes, struct GPUNodeLink *frag_outlink,
-        GPUVertexAttribs *attribs,
+        GPUMaterial *material,
+        GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs,
+        ListBase *nodes, ListBase *inputs,
         const char *vert_code, const char *geom_code,
         const char *frag_lib, const char *defines)
 {
+       char *vertexcode, *geometrycode, *fragmentcode;
        GPUShader *shader;
        GPUPass *pass;
-       char *vertexgen, *fragmentgen, *tmp;
-       char *vertexcode, *geometrycode, *fragmentcode;
 
        /* prune unused nodes */
        GPU_nodes_prune(nodes, frag_outlink);
 
        GPU_nodes_get_vertex_attributes(nodes, attribs);
 
-       /* generate code and compile with opengl */
-       fragmentgen = code_generate_fragment(material, nodes, 
frag_outlink->output, true);
-       vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != 
NULL));
+       /* generate code */
+       char *fragmentgen = code_generate_fragment(material, nodes, 
frag_outlink->output, true);
+       char *tmp = BLI_strdupcat(frag_lib, glsl_material_library);
 
-       tmp = BLI_strdupcat(frag_lib, glsl_material_library);
+       vertexcode = code_generate_vertex_new(nodes, vert_code, (geom_code != 
NULL));
+       geometrycode = (geom_code) ? code_generate_geometry_new(nodes, 
geom_code) : NULL;
        fragmentcode = BLI_strdupcat(tmp, fragmentgen);
-       vertexcode = BLI_strdup(vertexgen);
-
-       if (geom_code) {
-               geometrycode = code_generate_geometry_new(nodes, geom_code);
-       }
-       else {
-               geometrycode = NULL;
-       }
-
-       shader = GPU_shader_create(vertexcode,
-                                  fragmentcode,
-                                  geometrycode,
-                          

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to