mesa: change 'SHADER_SUBST' facility to work with env variables

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 <tapani.palli@intel.com>
Suggested-by: Eero Tamminen <eero.t.tamminen@intel.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
Tapani Pälli 2015-08-31 09:54:23 +03:00
parent 0db323a624
commit 04e201d0c0
2 changed files with 115 additions and 38 deletions

View File

@ -63,6 +63,20 @@ execution. These are generally used for debugging.
Example: export MESA_GLSL=dump,nopt
</p>
<p>
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:
<ul>
<li><b>MESA_SHADER_DUMP_PATH</b> - path where shader sources are dumped
<li><b>MESA_SHADER_READ_PATH</b> - path where replacement shaders are read
</ul>
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.
</p>
<h2 id="support">GLSL Version</h2>

View File

@ -53,15 +53,13 @@
#include "program/prog_parameter.h"
#include "util/ralloc.h"
#include "util/hash_table.h"
#include "util/mesa-sha1.h"
#include <stdbool.h>
#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:
*
* <path>/<stage prefix>_<CHECKSUM>.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 (!f) {
if (!path_exists)
return NULL;
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_<CHECKSUM>. 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);
/* 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);
_mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum);
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);
}