[Mesa-dev] [PATCH 83/87] glsl/i965: make a copy of the shader source and use it at fallback

Timothy Arceri timothy.arceri at collabora.com
Wed Jul 13 02:48:18 UTC 2016


A number of things can happen that change the shader source after it is
compiled or linked.

For example:
- Source changed after it is first compiled
- Source changed after linking
- Shader detached after linking

In order to be able to fallback to a full rebuild on a cache miss we
make a copy of the shader source it into the new FallbackShaders
field when linking.
---
 src/compiler/glsl/linker.cpp                 | 27 ++++++++++++++++-----------
 src/compiler/glsl/shader_cache.cpp           | 22 ++++++++++++++++++++++
 src/mesa/drivers/dri/i965/brw_shader_cache.c | 26 ++++++++++++++++++++------
 src/mesa/main/mtypes.h                       |  3 +++
 src/mesa/main/shaderobj.c                    |  6 ++++++
 src/mesa/program/ir_to_mesa.cpp              | 16 ++++++++++++----
 6 files changed, 79 insertions(+), 21 deletions(-)

diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp
index 5719c87..f782210 100644
--- a/src/compiler/glsl/linker.cpp
+++ b/src/compiler/glsl/linker.cpp
@@ -4500,7 +4500,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog,
     * fixed-function.  This applies to the case where all stages are
     * missing.
     */
-   if (prog->NumShaders == 0) {
+   unsigned shader_count = is_cache_fallback ?
+      prog->NumFallbackShaders : prog->NumShaders;
+   if (shader_count == 0) {
       if (ctx->API != API_OPENGL_COMPAT)
          linker_error(prog, "no shaders attached to the program\n");
       return;
@@ -4546,44 +4548,47 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog,
    struct gl_shader **shader_list[MESA_SHADER_STAGES];
    unsigned num_shaders[MESA_SHADER_STAGES];
 
+   struct gl_shader **shaders = is_cache_fallback ?
+      prog->FallbackShaders : prog->Shaders;
+
    for (int i = 0; i < MESA_SHADER_STAGES; i++) {
       shader_list[i] = (struct gl_shader **)
-         calloc(prog->NumShaders, sizeof(struct gl_shader *));
+         calloc(shader_count, sizeof(struct gl_shader *));
       num_shaders[i] = 0;
    }
 
    unsigned min_version = UINT_MAX;
    unsigned max_version = 0;
-   for (unsigned i = 0; i < prog->NumShaders; i++) {
-      min_version = MIN2(min_version, prog->Shaders[i]->Version);
-      max_version = MAX2(max_version, prog->Shaders[i]->Version);
+   for (unsigned i = 0; i < shader_count; i++) {
+      min_version = MIN2(min_version, shaders[i]->Version);
+      max_version = MAX2(max_version, shaders[i]->Version);
 
-      if (prog->Shaders[i]->IsES != prog->Shaders[0]->IsES) {
+      if (shaders[i]->IsES != shaders[0]->IsES) {
 	 linker_error(prog, "all shaders must use same shading "
 		      "language version\n");
 	 goto done;
       }
 
-      if (prog->Shaders[i]->info.ARB_fragment_coord_conventions_enable) {
+      if (shaders[i]->info.ARB_fragment_coord_conventions_enable) {
          prog->ARB_fragment_coord_conventions_enable = true;
       }
 
-      gl_shader_stage shader_type = prog->Shaders[i]->Stage;
-      shader_list[shader_type][num_shaders[shader_type]] = prog->Shaders[i];
+      gl_shader_stage shader_type = shaders[i]->Stage;
+      shader_list[shader_type][num_shaders[shader_type]] = shaders[i];
       num_shaders[shader_type]++;
    }
 
    /* In desktop GLSL, different shader versions may be linked together.  In
     * GLSL ES, all shader versions must be the same.
     */
-   if (prog->Shaders[0]->IsES && min_version != max_version) {
+   if (shaders[0]->IsES && min_version != max_version) {
       linker_error(prog, "all shaders must use same shading "
 		   "language version\n");
       goto done;
    }
 
    prog->Version = max_version;
-   prog->IsES = prog->Shaders[0]->IsES;
+   prog->IsES = shaders[0]->IsES;
 
    /* Some shaders have to be linked with some other shaders present.
     */
diff --git a/src/compiler/glsl/shader_cache.cpp b/src/compiler/glsl/shader_cache.cpp
index c661557..d27bc18 100644
--- a/src/compiler/glsl/shader_cache.cpp
+++ b/src/compiler/glsl/shader_cache.cpp
@@ -1168,6 +1168,28 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
    if (!cache)
       return false;
 
+   /* Shaders could be recompiled using different source code after linking,
+    * or the shader could be detached from the program so store some
+    * information about the shader to be used in case of fallback.
+    */
+   if (prog->FallbackShaders == NULL) {
+      prog->NumFallbackShaders = prog->NumShaders;
+      prog->FallbackShaders = (struct gl_shader **)
+         reralloc(NULL, prog->FallbackShaders, struct gl_shader *,
+                  prog->NumShaders);
+      for (unsigned i = 0; i < prog->NumShaders; i++) {
+         prog->FallbackShaders[i] = rzalloc(prog->FallbackShaders,
+                                            struct gl_shader);
+         memcpy(prog->FallbackShaders[i]->sha1, prog->Shaders[i]->sha1,
+                sizeof(prog->Shaders[i]->sha1));
+         prog->FallbackShaders[i]->Stage = prog->Shaders[i]->Stage;
+         prog->FallbackShaders[i]->Source =
+            ralloc_strdup(prog->FallbackShaders, prog->Shaders[i]->Source);
+         prog->FallbackShaders[i]->InfoLog =
+            ralloc_strdup(prog->FallbackShaders, "");
+      }
+   }
+
    for (unsigned i = 0; i < prog->NumShaders; i++) {
       if (prog->Shaders[i]->Stage == MESA_SHADER_COMPUTE) {
          compile_shaders(ctx, prog);
diff --git a/src/mesa/drivers/dri/i965/brw_shader_cache.c b/src/mesa/drivers/dri/i965/brw_shader_cache.c
index 6e3b6e9..80086a5 100644
--- a/src/mesa/drivers/dri/i965/brw_shader_cache.c
+++ b/src/mesa/drivers/dri/i965/brw_shader_cache.c
@@ -189,12 +189,19 @@ fallback_to_full_recompile(struct brw_context *brw,
       if (fp)
          fp->cache_fallback = true;
 
-      for (unsigned i = 0; i < shProg->NumShaders; i++) {
-         _mesa_glsl_compile_shader(&brw->ctx, shProg->Shaders[i], false,
-                                   false, true);
+      for (unsigned i = 0; i < shProg->NumFallbackShaders; i++) {
+         _mesa_glsl_compile_shader(&brw->ctx, shProg->FallbackShaders[i],
+                                   false, false, true);
       }
       _mesa_glsl_link_shader(&brw->ctx, shProg, true);
 
+      /* We should never get here again so free the shaders */
+      shProg->NumFallbackShaders = 0;
+      for (unsigned i = 0; i < shProg->NumFallbackShaders; i++) {
+         ralloc_free(shProg->FallbackShaders);
+         shProg->FallbackShaders = NULL;
+      }
+
       vp->cache_fallback = false;
       if (tcp)
          tcp->cache_fallback = true;
@@ -215,12 +222,19 @@ fallback_to_full_recompile(struct brw_context *brw,
 
       fp->cache_fallback = true;
 
-      for (unsigned i = 0; i < shProg->NumShaders; i++) {
-         _mesa_glsl_compile_shader(&brw->ctx, shProg->Shaders[i], false,
-                                   false, true);
+      for (unsigned i = 0; i < shProg->NumFallbackShaders; i++) {
+         _mesa_glsl_compile_shader(&brw->ctx, shProg->FallbackShaders[i],
+                                   false, false, true);
       }
       _mesa_glsl_link_shader(&brw->ctx, shProg, true);
 
+      /* We should never get here again so free the shaders */
+      shProg->NumFallbackShaders = 0;
+      for (unsigned i = 0; i < shProg->NumFallbackShaders; i++) {
+         ralloc_free(shProg->FallbackShaders);
+         shProg->FallbackShaders = NULL;
+      }
+
       fp->cache_fallback = false;
    }
 }
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index d7d5e18..f2cb020 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2699,6 +2699,9 @@ struct gl_shader_program
    GLuint NumShaders;          /**< number of attached shaders */
    struct gl_shader **Shaders; /**< List of attached the shaders */
 
+   GLuint NumFallbackShaders;
+   struct gl_shader **FallbackShaders; /**< Shaders used for cache fallback */
+
    /**
     * User-defined attribute bindings
     *
diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c
index 0fcb469..f114cf5 100644
--- a/src/mesa/main/shaderobj.c
+++ b/src/mesa/main/shaderobj.c
@@ -377,10 +377,16 @@ _mesa_free_shader_program_data(struct gl_context *ctx,
       _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
    }
    shProg->NumShaders = 0;
+   shProg->NumFallbackShaders = 0;
 
    free(shProg->Shaders);
    shProg->Shaders = NULL;
 
+   if (shProg->FallbackShaders){
+      ralloc_free(shProg->FallbackShaders);
+      shProg->FallbackShaders = NULL;
+   }
+
    /* Transform feedback varying vars */
    for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
       free(shProg->TransformFeedback.VaryingNames[i]);
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 4978095..dae364d 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -3061,9 +3061,11 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog,
 
    prog->LinkStatus = GL_TRUE;
 
-   for (i = 0; i < prog->NumShaders; i++) {
-      if (!prog->Shaders[i]->CompileStatus) {
-	 linker_error(prog, "linking with uncompiled shader");
+   if (!is_cache_fallback) {
+      for (i = 0; i < prog->NumShaders; i++) {
+         if (!prog->Shaders[i]->CompileStatus) {
+	    linker_error(prog, "linking with uncompiled shader");
+         }
       }
    }
 
@@ -3097,8 +3099,14 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog,
    }
 
 #ifdef ENABLE_SHADER_CACHE
-   if (prog->LinkStatus)
+   if (prog->LinkStatus && !is_cache_fallback) {
+      if (prog->FallbackShaders) {
+         prog->NumFallbackShaders = 0;
+         ralloc_free(prog->FallbackShaders);
+         prog->FallbackShaders = NULL;
+      }
       shader_cache_write_program_metadata(ctx, prog);
+   }
 #endif
 }
 
-- 
2.7.4



More information about the mesa-dev mailing list