[Mesa-dev] [RFC PATCH] Change the shader capture naming system from purely number based to sha_number

Benedikt Schemmer ben at besd.de
Fri Apr 6 09:11:16 UTC 2018


Depending on the application captured shaders may or may not be the same
when they have the same number.
In Games it often depends on the users graphics options.

This is a problem when running shader-db and looking at the output.
There the same shader number can mean entirely different shaders
depending on user settings in an application.
Also different numbers can mean the exact same shader.

A good example of this is Metro 2033 Redux, where on the one hand the
same shader is compiled dozens of times resulting in dozens of identical
shaders with different numbers and on the other hand the same number is
used for entirely different shaders when the graphics options are changed.

examples from metro
ff92ec1631322329e8c6125184b7681f190a2c73_11179.shader_test
ff92ec1631322329e8c6125184b7681f190a2c73_12166.shader_test
ff92ec1631322329e8c6125184b7681f190a2c73_13493.shader_test
ff92ec1631322329e8c6125184b7681f190a2c73_1956.shader_test
ff92ec1631322329e8c6125184b7681f190a2c73_3939.shader_test
ff92ec1631322329e8c6125184b7681f190a2c73_5042.shader_test
ff92ec1631322329e8c6125184b7681f190a2c73_9394.shader_test

639f9dd8dc9ccd6465c203d2483c6f1b1838ae19_1109.shader_test size: 2,2K
f70e06b31f68b96b1d5b0b3b4966cfbe02d51c44_1109.shader_test size: 4,0K

A number at the end seems to be necessary to avoid race conditions when
the application tries to compile the same shader multiple times at the
same time.

Tested with several 64-bit Games like Dirt Rally and Metro 2033 Redux.

I am not sure if this should be a series of smaller patches or if it can
be just one large blob.
Also I dont know where exactly the ENABLE_SHADER_CACHE code should be
put one helper function is used to generate the sha.

Please kindly review and push, if you find this useful.

---
 src/mesa/main/shaderapi.c | 272
++++++++++++++++++++++++----------------------
 1 file changed, 145 insertions(+), 127 deletions(-)

diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index 76bad7f31e..1e35f055a6 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -65,6 +65,122 @@
 #include "util/mesa-sha1.h"
 #include "util/crc32.h"

+
+/**
+ * Generate a SHA-1 hash value string for given source string.
+ */
+static void
+generate_sha1(const char *source, char sha_str[64])
+{
+   unsigned char sha[20];
+   _mesa_sha1_compute(source, strlen(source), sha);
+   _mesa_sha1_format(sha_str, sha);
+}
+
+
+#ifdef ENABLE_SHADER_CACHE
+/**
+ * Construct a full path for shader replacement functionality using
+ * following format:
+ *
+ * <path>/<stage prefix>_<CHECKSUM>.glsl
+ */
+static char *
+construct_name(const gl_shader_stage stage, const char *source,
+               const char *path)
+{
+   char sha[64];
+   static const char *types[] = {
+      "VS", "TC", "TE", "GS", "FS", "CS",
+   };
+
+   generate_sha1(source, sha);
+   return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha);
+}
+
+/**
+ * Write given shader source to a file in MESA_SHADER_DUMP_PATH.
+ */
+static void
+dump_shader(const gl_shader_stage stage, const char *source)
+{
+   static bool path_exists = true;
+   char *dump_path;
+   FILE *f;
+
+   if (!path_exists)
+      return;
+
+   dump_path = getenv("MESA_SHADER_DUMP_PATH");
+   if (!dump_path) {
+      path_exists = false;
+      return;
+   }
+
+   char *name = construct_name(stage, source, dump_path);
+
+   f = fopen(name, "w");
+   if (f) {
+      fputs(source, f);
+      fclose(f);
+   } else {
+      GET_CURRENT_CONTEXT(ctx);
+      _mesa_warning(ctx, "could not open %s for dumping shader (%s)", name,
+                    strerror(errno));
+   }
+   ralloc_free(name);
+}
+
+/**
+ * Read shader source code from a file.
+ * Useful for debugging to override an app's shader.
+ */
+static GLcharARB *
+read_shader(const gl_shader_stage stage, const char *source)
+{
+   char *read_path;
+   static bool path_exists = true;
+   int len, shader_size = 0;
+   GLcharARB *buffer;
+   FILE *f;
+
+   if (!path_exists)
+      return NULL;
+
+   read_path = getenv("MESA_SHADER_READ_PATH");
+   if (!read_path) {
+      path_exists = false;
+      return NULL;
+   }
+
+   char *name = construct_name(stage, source, read_path);
+   f = fopen(name, "r");
+   ralloc_free(name);
+   if (!f)
+      return NULL;
+
+   /* allocate enough room for the entire shader */
+   fseek(f, 0, SEEK_END);
+   shader_size = ftell(f);
+   rewind(f);
+   assert(shader_size);
+
+   /* add one for terminating zero */
+   shader_size++;
+
+   buffer = malloc(shader_size);
+   assert(buffer);
+
+   len = fread(buffer, 1, shader_size, f);
+   buffer[len] = 0;
+
+   fclose(f);
+
+   return buffer;
+}
+
+#endif /* ENABLE_SHADER_CACHE */
+
 /**
  * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
  */
@@ -1228,29 +1344,43 @@ link_program(struct gl_context *ctx, struct
gl_shader_program *shProg,
    /* Capture .shader_test files. */
    const char *capture_path = _mesa_get_shader_capture_path();
    if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) {
+
       FILE *file;
-      char *filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
-                                       capture_path, shProg->Name);
+      char *filename = NULL;
+      char *fsource = NULL;
+      char *ftemp = NULL;
+
+      asprintf(&fsource, "[require]\nGLSL%s >= %u.%02u\n", shProg->IsES
? " ES" : "",
+               shProg->data->Version / 100, shProg->data->Version % 100);
+
+      if (shProg->SeparateShader) {
+         ftemp = fsource;
+         asprintf(&fsource, "%sGL_ARB_separate_shader_objects\nSSO
ENABLED\n", ftemp);
+         free(ftemp);
+      }
+
+      for (unsigned i = 0; i < shProg->NumShaders; i++) {
+          ftemp = fsource;
+          asprintf(&fsource, "%s\n[%s shader]\n%s\n", ftemp,
+                   _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
+                   shProg->Shaders[i]->Source);
+          free(ftemp);
+      }
+
+      char shabuf[64] = {"mylittlebunny"};
+      generate_sha1(fsource, shabuf);
+
+      asprintf(&filename, "%s/%s_%u.shader_test", capture_path,
shabuf,shProg->Name);
       file = fopen(filename, "w");
       if (file) {
-         fprintf(file, "[require]\nGLSL%s >= %u.%02u\n",
-                 shProg->IsES ? " ES" : "",
-                 shProg->data->Version / 100, shProg->data->Version % 100);
-         if (shProg->SeparateShader)
-            fprintf(file, "GL_ARB_separate_shader_objects\nSSO ENABLED\n");
-         fprintf(file, "\n");
-
-         for (unsigned i = 0; i < shProg->NumShaders; i++) {
-            fprintf(file, "[%s shader]\n%s\n",
-
_mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
-                    shProg->Shaders[i]->Source);
-         }
+         fprintf(file, "%s", fsource);
          fclose(file);
       } else {
          _mesa_warning(ctx, "Failed to open %s", filename);
       }

-      ralloc_free(filename);
+      free(filename);
+      free(fsource);
    }

    if (shProg->data->LinkStatus == LINKING_FAILURE &&
@@ -1776,119 +1906,7 @@ _mesa_LinkProgram(GLuint programObj)
    link_program_error(ctx, shProg);
 }

-#ifdef ENABLE_SHADER_CACHE
-/**
- * Generate a SHA-1 hash value string for given source string.
- */
-static void
-generate_sha1(const char *source, char sha_str[64])
-{
-   unsigned char sha[20];
-   _mesa_sha1_compute(source, strlen(source), sha);
-   _mesa_sha1_format(sha_str, sha);
-}
-
-/**
- * Construct a full path for shader replacement functionality using
- * following format:
- *
- * <path>/<stage prefix>_<CHECKSUM>.glsl
- */
-static char *
-construct_name(const gl_shader_stage stage, const char *source,
-               const char *path)
-{
-   char sha[64];
-   static const char *types[] = {
-      "VS", "TC", "TE", "GS", "FS", "CS",
-   };
-
-   generate_sha1(source, sha);
-   return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha);
-}
-
-/**
- * Write given shader source to a file in MESA_SHADER_DUMP_PATH.
- */
-static void
-dump_shader(const gl_shader_stage stage, const char *source)
-{
-   static bool path_exists = true;
-   char *dump_path;
-   FILE *f;
-
-   if (!path_exists)
-      return;
-
-   dump_path = getenv("MESA_SHADER_DUMP_PATH");
-   if (!dump_path) {
-      path_exists = false;
-      return;
-   }
-
-   char *name = construct_name(stage, source, dump_path);
-
-   f = fopen(name, "w");
-   if (f) {
-      fputs(source, f);
-      fclose(f);
-   } else {
-      GET_CURRENT_CONTEXT(ctx);
-      _mesa_warning(ctx, "could not open %s for dumping shader (%s)", name,
-                    strerror(errno));
-   }
-   ralloc_free(name);
-}
-
-/**
- * Read shader source code from a file.
- * Useful for debugging to override an app's shader.
- */
-static GLcharARB *
-read_shader(const gl_shader_stage stage, const char *source)
-{
-   char *read_path;
-   static bool path_exists = true;
-   int len, shader_size = 0;
-   GLcharARB *buffer;
-   FILE *f;
-
-   if (!path_exists)
-      return NULL;

-   read_path = getenv("MESA_SHADER_READ_PATH");
-   if (!read_path) {
-      path_exists = false;
-      return NULL;
-   }
-
-   char *name = construct_name(stage, source, read_path);
-   f = fopen(name, "r");
-   ralloc_free(name);
-   if (!f)
-      return NULL;
-
-   /* allocate enough room for the entire shader */
-   fseek(f, 0, SEEK_END);
-   shader_size = ftell(f);
-   rewind(f);
-   assert(shader_size);
-
-   /* add one for terminating zero */
-   shader_size++;
-
-   buffer = malloc(shader_size);
-   assert(buffer);
-
-   len = fread(buffer, 1, shader_size, f);
-   buffer[len] = 0;
-
-   fclose(f);
-
-   return buffer;
-}
-
-#endif /* ENABLE_SHADER_CACHE */

 /**
  * Called via glShaderSource() and glShaderSourceARB() API functions.
-- 
2.14.1


More information about the mesa-dev mailing list