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:
parent
0db323a624
commit
04e201d0c0
|
@ -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>
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue