*/
+#include <stdbool.h>
#include "main/glheader.h"
#include "main/context.h"
#include "main/dispatch.h"
#include "main/shaderobj.h"
#include "main/transformfeedback.h"
#include "main/uniforms.h"
+#include "glsl/glsl_parser_extras.h"
+#include "glsl/ir.h"
+#include "glsl/ir_uniform.h"
+#include "glsl/program.h"
#include "program/program.h"
#include "program/prog_print.h"
#include "program/prog_parameter.h"
#include "util/ralloc.h"
#include "util/hash_table.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
+#include "util/mesa-sha1.h"
/**
name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
- shProg = ctx->Driver.NewShaderProgram(name);
+ shProg = _mesa_new_shader_program(name);
_mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
if (!has_ubo)
break;
- for (i = 0; i < shProg->NumUniformBlocks; i++) {
+ for (i = 0; i < shProg->NumBufferInterfaceBlocks; i++) {
/* Add one for the terminating NUL character.
*/
- const GLint len = strlen(shProg->UniformBlocks[i].Name) + 1;
+ const GLint len = strlen(shProg->BufferInterfaceBlocks[i].Name) + 1;
if (len > max_len)
max_len = len;
return;
case GL_COMPUTE_WORK_GROUP_SIZE: {
int i;
- if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_compute_shader)
+ if (!_mesa_has_compute_shaders(ctx))
break;
if (!shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(program not "
return;
}
case GL_PROGRAM_SEPARABLE:
- *params = shProg->SeparateShader;
+ /* If the program has not been linked, return initial value 0. */
+ *params = (shProg->LinkStatus == GL_FALSE) ? 0 : shProg->SeparateShader;
return;
/* ARB_tessellation_shader */
* glShaderSource[ARB].
*/
static void
-shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
+shader_source(struct gl_shader *sh, const GLchar *source)
{
- struct gl_shader *sh;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
- if (!sh)
- return;
+ assert(sh);
/* free old shader source string and install new one */
free((void *)sh->Source);
_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname,
GLfloat *params)
{
- GLint iparams[1]; /* XXX is one element enough? */
+ GLint iparams[1] = {0}; /* XXX is one element enough? */
_mesa_GetObjectParameterivARB(object, pname, iparams);
params[0] = (GLfloat) iparams[0];
}
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 (!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);
fclose(f);
- shader = strdup(buffer);
- free(buffer);
-
- return shader;
+ return buffer;
}
-
+#endif /* HAVE_SHA1 */
/**
* Called via glShaderSource() and glShaderSourceARB() API functions.
*/
void GLAPIENTRY
_mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count,
- const GLcharARB * const * string, const GLint * length)
+ const GLcharARB * const * string, const GLint * length)
{
GET_CURRENT_CONTEXT(ctx);
GLint *offsets;
GLsizei i, totalLength;
GLcharARB *source;
- GLuint checksum;
+ struct gl_shader *sh;
- if (!shaderObj || string == NULL) {
+#if defined(HAVE_SHA1)
+ GLcharARB *replacement;
+#endif /* HAVE_SHA1 */
+
+ sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB");
+ if (!sh)
+ return;
+
+ if (string == NULL) {
_mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
return;
}
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;
-
- checksum = _mesa_str_checksum(source);
-
- _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum);
+#if defined(HAVE_SHA1)
+ /* 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 */
- }
+ shader_source(sh, source);
free(offsets);
}
const void* binary, GLint length)
{
GET_CURRENT_CONTEXT(ctx);
- (void) n;
(void) shaders;
(void) binaryformat;
(void) binary;
- (void) length;
- _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderBinary");
+
+ /* Page 68, section 7.2 'Shader Binaries" of the of the OpenGL ES 3.1, and
+ * page 88 of the OpenGL 4.5 specs state:
+ *
+ * "An INVALID_VALUE error is generated if count or length is negative.
+ * An INVALID_ENUM error is generated if binaryformat is not a supported
+ * format returned in SHADER_BINARY_FORMATS."
+ */
+ if (n < 0 || length < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glShaderBinary(count or length < 0)");
+ return;
+ }
+
+ _mesa_error(ctx, GL_INVALID_ENUM, "glShaderBinary(format)");
}
}
-static GLuint
-_mesa_create_shader_program(struct gl_context* ctx, GLboolean separate,
- GLenum type, GLsizei count, const GLchar* const *strings)
-{
- const GLuint shader = create_shader(ctx, type);
- GLuint program = 0;
-
- if (shader) {
- _mesa_ShaderSource(shader, count, strings, NULL);
-
- compile_shader(ctx, shader);
-
- program = create_shader_program(ctx);
- if (program) {
- struct gl_shader_program *shProg;
- struct gl_shader *sh;
- GLint compiled = GL_FALSE;
-
- shProg = _mesa_lookup_shader_program(ctx, program);
- sh = _mesa_lookup_shader(ctx, shader);
-
- shProg->SeparateShader = separate;
-
- get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
- if (compiled) {
- attach_shader(ctx, program, shader);
- link_program(ctx, program);
- detach_shader(ctx, program, shader);
-
-#if 0
- /* Possibly... */
- if (active-user-defined-varyings-in-linked-program) {
- append-error-to-info-log;
- shProg->LinkStatus = GL_FALSE;
- }
-#endif
- }
-
- ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
- }
-
- delete_shader(ctx, shader);
- }
-
- return program;
-}
-
-
/**
* Copy program-specific data generated by linking from the gl_shader_program
* object to a specific gl_program object.
dst->UsesClipDistanceOut = src->Geom.UsesClipDistance;
dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
dst_gp->UsesStreams = src->Geom.UsesStreams;
- }
break;
+ }
case MESA_SHADER_FRAGMENT: {
struct gl_fragment_program *dst_fp = (struct gl_fragment_program *) dst;
dst_fp->FragDepthLayout = src->FragDepthLayout;
- }
break;
+ }
case MESA_SHADER_COMPUTE: {
struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst;
int i;
for (i = 0; i < 3; i++)
dst_cp->LocalSize[i] = src->Comp.LocalSize[i];
- }
break;
+ }
default:
break;
}
{
GET_CURRENT_CONTEXT(ctx);
- return _mesa_create_shader_program(ctx, GL_TRUE, type, count, strings);
+ const GLuint shader = create_shader(ctx, type);
+ GLuint program = 0;
+
+ /*
+ * According to OpenGL 4.5 and OpenGL ES 3.1 standards, section 7.3:
+ * GL_INVALID_VALUE should be generated if count < 0
+ */
+ if (count < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glCreateShaderProgram (count < 0)");
+ return program;
+ }
+
+ if (shader) {
+ _mesa_ShaderSource(shader, count, strings, NULL);
+
+ compile_shader(ctx, shader);
+
+ program = create_shader_program(ctx);
+ if (program) {
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ GLint compiled = GL_FALSE;
+
+ shProg = _mesa_lookup_shader_program(ctx, program);
+ sh = _mesa_lookup_shader(ctx, shader);
+
+ shProg->SeparateShader = GL_TRUE;
+
+ get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
+ if (compiled) {
+ attach_shader(ctx, program, shader);
+ link_program(ctx, program);
+ detach_shader(ctx, program, shader);
+
+#if 0
+ /* Possibly... */
+ if (active-user-defined-varyings-in-linked-program) {
+ append-error-to-info-log;
+ shProg->LinkStatus = GL_FALSE;
+ }
+#endif
+ }
+ if (sh->InfoLog)
+ ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
+ }
+
+ delete_shader(ctx, shader);
+ }
+
+ return program;
}
gl_shader_stage stage;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
if (!shProg->_LinkedShaders[stage]) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
gl_shader_stage stage;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
if (!shProg->_LinkedShaders[stage]) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
resource_type = _mesa_shader_stage_to_subroutine(stage);
- res = _mesa_program_resource_find_name(shProg, resource_type, name);
+ res = _mesa_program_resource_find_name(shProg, resource_type, name, NULL);
if (!res) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
int count, i, j;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
sh = shProg->_LinkedShaders[stage];
if (!sh) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
case GL_UNIFORM_NAME_LENGTH:
res = _mesa_program_resource_find_index(shProg, resource_type, index);
if (res) {
- values[0] = strlen(_mesa_program_resource_name(res)) + 1 + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);;
+ values[0] = strlen(_mesa_program_resource_name(res)) + 1
+ + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);;
}
break;
default:
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
}
gl_shader_stage stage;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
if (!shProg->_LinkedShaders[stage]) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
gl_shader_stage stage;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
if (!shProg->_LinkedShaders[stage]) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
resource_type = _mesa_shader_stage_to_subroutine(stage);
int i;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
shProg = ctx->_Shader->CurrentProgram[stage];
if (!shProg) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
sh = shProg->_LinkedShaders[stage];
if (!sh) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (count != sh->NumSubroutineUniformRemapTable) {
- _mesa_error(ctx, GL_INVALID_VALUE, api_name);
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
return;
}
for (j = i; j < i + uni_count; j++) {
struct gl_subroutine_function *subfn;
if (indices[j] >= sh->NumSubroutineFunctions) {
- _mesa_error(ctx, GL_INVALID_VALUE, api_name);
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
return;
}
break;
}
if (k == subfn->num_compat_types) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
}
gl_shader_stage stage;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
shProg = ctx->_Shader->CurrentProgram[stage];
if (!shProg) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
sh = shProg->_LinkedShaders[stage];
if (!sh) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (location >= sh->NumSubroutineUniformRemapTable) {
- _mesa_error(ctx, GL_INVALID_VALUE, api_name);
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
return;
}
{
struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[location];
- int offset = location - uni->subroutine[stage].index;
+ int offset = location - uni->opaque[stage].index;
memcpy(params, &uni->storage[offset],
sizeof(GLuint));
}
gl_shader_stage stage;
if (!_mesa_has_shader_subroutine(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
if (!_mesa_validate_shader_target(ctx, shadertype)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
sh = shProg->_LinkedShaders[stage];
if (!sh) {
- _mesa_error(ctx, GL_INVALID_OPERATION, api_name);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
res = _mesa_program_resource_find_index(shProg, resource_type, i);
if (res) {
- const GLint len = strlen(_mesa_program_resource_name(res)) + 1+ ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);
+ const GLint len = strlen(_mesa_program_resource_name(res)) + 1
+ + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);
if (len > max_len)
max_len = len;
break;
}
default:
- _mesa_error(ctx, GL_INVALID_ENUM, api_name);
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s", api_name);
values[0] = -1;
break;
}