From 04e201d0c02cd30ace5c6fe80e9f021ebb733682 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tapani=20P=C3=A4lli?= Date: Mon, 31 Aug 2015 09:54:23 +0300 Subject: [PATCH] mesa: change 'SHADER_SUBST' facility to work with env variables MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Patch modifies existing shader source and replace functionality to work with environment variables rather than enable dumping on compile time. Also instead of _mesa_str_checksum, _mesa_sha1_compute is used to avoid collisions. Functionality is controlled via two environment variables: MESA_SHADER_DUMP_PATH - path where shader sources are dumped MESA_SHADER_READ_PATH - path where replacement shaders are read v2: cleanups, add strerror if fopen fails, put all functionality inside HAVE_SHA1 since sha1 is required Signed-off-by: Tapani Pälli Suggested-by: Eero Tamminen Reviewed-by: Brian Paul --- docs/shading.html | 14 ++++ src/mesa/main/shaderapi.c | 139 +++++++++++++++++++++++++++----------- 2 files changed, 115 insertions(+), 38 deletions(-) diff --git a/docs/shading.html b/docs/shading.html index 77a0ee413d9..e9fe3dde166 100644 --- a/docs/shading.html +++ b/docs/shading.html @@ -63,6 +63,20 @@ execution. These are generally used for debugging. Example: export MESA_GLSL=dump,nopt

+

+Shaders can be dumped and replaced on runtime for debugging purposes. Mesa +needs to be configured with '--with-sha1' to enable this functionality. This +feature is not currently supported by SCons build. + +This is controlled via following environment variables: +

    +
  • MESA_SHADER_DUMP_PATH - path where shader sources are dumped +
  • MESA_SHADER_READ_PATH - path where replacement shaders are read +
+Note, path set must exist before running for dumping or replacing to work. +When both are set, these paths should be different so the dumped shaders do +not clobber the replacement shaders. +

GLSL Version

diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 0e0e0d6ba30..7680b5875b2 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -53,15 +53,13 @@ #include "program/prog_parameter.h" #include "util/ralloc.h" #include "util/hash_table.h" +#include "util/mesa-sha1.h" #include #include "../glsl/glsl_parser_extras.h" #include "../glsl/ir.h" #include "../glsl/ir_uniform.h" #include "../glsl/program.h" -/** Define this to enable shader substitution (see below) */ -#define SHADER_SUBST 0 - /** * Return mask of GLSL_x flags by examining the MESA_GLSL env var. @@ -1512,24 +1510,100 @@ _mesa_LinkProgram(GLhandleARB programObj) link_program(ctx, programObj); } +#if defined(HAVE_SHA1) +/** + * 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: + * + * /_.glsl + */ +static void +construct_name(const gl_shader_stage stage, const char *source, + const char *path, char *name, unsigned length) +{ + char sha[64]; + static const char *types[] = { + "VS", "TC", "TE", "GS", "FS", "CS", + }; + + generate_sha1(source, sha); + _mesa_snprintf(name, length, "%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) +{ + char name[PATH_MAX]; + 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; + } + construct_name(stage, source, dump_path, name, PATH_MAX); + + 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)); + } +} /** * Read shader source code from a file. * Useful for debugging to override an app's shader. */ static GLcharARB * -read_shader(const char *fname) +read_shader(const gl_shader_stage stage, const char *source) { - int shader_size = 0; - FILE *f = fopen(fname, "r"); - GLcharARB *buffer, *shader; - int len; + char name[PATH_MAX]; + char *read_path; + static bool path_exists = true; + int len, shader_size = 0; + GLcharARB *buffer; + FILE *f; + + if (!path_exists) + return NULL; - if (!f) { + read_path = getenv("MESA_SHADER_READ_PATH"); + if (!read_path) { + path_exists = false; return NULL; } + construct_name(stage, source, read_path, name, PATH_MAX); + + f = fopen(name, "r"); + if (!f) + return NULL; + /* allocate enough room for the entire shader */ fseek(f, 0, SEEK_END); shader_size = ftell(f); @@ -1547,12 +1621,9 @@ read_shader(const char *fname) fclose(f); - shader = strdup(buffer); - free(buffer); - - return shader; + return buffer; } - +#endif /* HAVE_SHA1 */ /** * Called via glShaderSource() and glShaderSourceARB() API functions. @@ -1567,7 +1638,11 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count, GLint *offsets; GLsizei i, totalLength; GLcharARB *source; - GLuint checksum; + +#if defined(HAVE_SHA1) + GLcharARB *replacement; + struct gl_shader *sh; +#endif /* HAVE_SHA1 */ if (!shaderObj || string == NULL) { _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); @@ -1620,35 +1695,23 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count, source[totalLength - 1] = '\0'; source[totalLength - 2] = '\0'; - if (SHADER_SUBST) { - /* Compute the shader's source code checksum then try to open a file - * named newshader_. If it exists, use it in place of the - * original shader source code. For debugging. - */ - char filename[100]; - GLcharARB *newSource; +#if defined(HAVE_SHA1) + sh = _mesa_lookup_shader(ctx, shaderObj); - checksum = _mesa_str_checksum(source); - - _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); + /* Dump original shader source to MESA_SHADER_DUMP_PATH and replace + * if corresponding entry found from MESA_SHADER_READ_PATH. + */ + dump_shader(sh->Stage, source); - newSource = read_shader(filename); - if (newSource) { - fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", - shaderObj, checksum, filename); - free(source); - source = newSource; - } + replacement = read_shader(sh->Stage, source); + if (replacement) { + free(source); + source = replacement; } +#endif /* HAVE_SHA1 */ shader_source(ctx, shaderObj, source); - if (SHADER_SUBST) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); - if (sh) - sh->SourceChecksum = checksum; /* save original checksum */ - } - free(offsets); } -- 2.30.2