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
|
Example: export MESA_GLSL=dump,nopt
|
||||||
</p>
|
</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>
|
<h2 id="support">GLSL Version</h2>
|
||||||
|
|
||||||
|
|
|
@ -53,15 +53,13 @@
|
||||||
#include "program/prog_parameter.h"
|
#include "program/prog_parameter.h"
|
||||||
#include "util/ralloc.h"
|
#include "util/ralloc.h"
|
||||||
#include "util/hash_table.h"
|
#include "util/hash_table.h"
|
||||||
|
#include "util/mesa-sha1.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "../glsl/glsl_parser_extras.h"
|
#include "../glsl/glsl_parser_extras.h"
|
||||||
#include "../glsl/ir.h"
|
#include "../glsl/ir.h"
|
||||||
#include "../glsl/ir_uniform.h"
|
#include "../glsl/ir_uniform.h"
|
||||||
#include "../glsl/program.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.
|
* 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);
|
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.
|
* Read shader source code from a file.
|
||||||
* Useful for debugging to override an app's shader.
|
* Useful for debugging to override an app's shader.
|
||||||
*/
|
*/
|
||||||
static GLcharARB *
|
static GLcharARB *
|
||||||
read_shader(const char *fname)
|
read_shader(const gl_shader_stage stage, const char *source)
|
||||||
{
|
{
|
||||||
int shader_size = 0;
|
char name[PATH_MAX];
|
||||||
FILE *f = fopen(fname, "r");
|
char *read_path;
|
||||||
GLcharARB *buffer, *shader;
|
static bool path_exists = true;
|
||||||
int len;
|
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;
|
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 */
|
/* allocate enough room for the entire shader */
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
shader_size = ftell(f);
|
shader_size = ftell(f);
|
||||||
|
@ -1547,12 +1621,9 @@ read_shader(const char *fname)
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
shader = strdup(buffer);
|
return buffer;
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_SHA1 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called via glShaderSource() and glShaderSourceARB() API functions.
|
* Called via glShaderSource() and glShaderSourceARB() API functions.
|
||||||
|
@ -1567,7 +1638,11 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
|
||||||
GLint *offsets;
|
GLint *offsets;
|
||||||
GLsizei i, totalLength;
|
GLsizei i, totalLength;
|
||||||
GLcharARB *source;
|
GLcharARB *source;
|
||||||
GLuint checksum;
|
|
||||||
|
#if defined(HAVE_SHA1)
|
||||||
|
GLcharARB *replacement;
|
||||||
|
struct gl_shader *sh;
|
||||||
|
#endif /* HAVE_SHA1 */
|
||||||
|
|
||||||
if (!shaderObj || string == NULL) {
|
if (!shaderObj || string == NULL) {
|
||||||
_mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
|
_mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
|
||||||
|
@ -1620,35 +1695,23 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
|
||||||
source[totalLength - 1] = '\0';
|
source[totalLength - 1] = '\0';
|
||||||
source[totalLength - 2] = '\0';
|
source[totalLength - 2] = '\0';
|
||||||
|
|
||||||
if (SHADER_SUBST) {
|
#if defined(HAVE_SHA1)
|
||||||
/* Compute the shader's source code checksum then try to open a file
|
sh = _mesa_lookup_shader(ctx, shaderObj);
|
||||||
* named newshader_<CHECKSUM>. If it exists, use it in place of the
|
|
||||||
* original shader source code. For debugging.
|
|
||||||
*/
|
|
||||||
char filename[100];
|
|
||||||
GLcharARB *newSource;
|
|
||||||
|
|
||||||
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);
|
replacement = read_shader(sh->Stage, source);
|
||||||
|
if (replacement) {
|
||||||
newSource = read_shader(filename);
|
free(source);
|
||||||
if (newSource) {
|
source = replacement;
|
||||||
fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n",
|
|
||||||
shaderObj, checksum, filename);
|
|
||||||
free(source);
|
|
||||||
source = newSource;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_SHA1 */
|
||||||
|
|
||||||
shader_source(ctx, shaderObj, source);
|
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);
|
free(offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue