From 72f2c55069f167a46560005931382e3b472f92ed Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 4 Apr 2008 11:20:44 -0600 Subject: gallium: make sure to set the SamplersUsed field for bitmap/drawpixels shaders Also, make sure that field is copied/updated in the program clone and combine functions. Without this we weren't getting SAMP declarations in the TGSI shaders. --- src/mesa/shader/program.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index 09a8494bd3..3069b04836 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -361,6 +361,7 @@ _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog) prog->NumInstructions); clone->InputsRead = prog->InputsRead; clone->OutputsWritten = prog->OutputsWritten; + clone->SamplersUsed = prog->SamplersUsed; memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); if (prog->Parameters) @@ -537,6 +538,7 @@ _mesa_combine_programs(GLcontext *ctx, } newProg->InputsRead = progA->InputsRead | inputsB; newProg->OutputsWritten = progB->OutputsWritten; + newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; } else { /* vertex program */ -- cgit v1.2.3 From b8cc9e88e067a5cd6a1acbae6d6a314e9165652f Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 4 Apr 2008 18:57:40 -0600 Subject: mesa: new functions for managing list/index of uniforms --- src/mesa/shader/prog_uniform.c | 157 +++++++++++++++++++++++++++++++++++++++++ src/mesa/shader/prog_uniform.h | 91 ++++++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 src/mesa/shader/prog_uniform.c create mode 100644 src/mesa/shader/prog_uniform.h (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/prog_uniform.c b/src/mesa/shader/prog_uniform.c new file mode 100644 index 0000000000..20e004b350 --- /dev/null +++ b/src/mesa/shader/prog_uniform.c @@ -0,0 +1,157 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_uniform.c + * Shader uniform functions. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/mtypes.h" +#include "prog_uniform.h" + + +struct gl_uniform_list * +_mesa_new_uniform_list(void) +{ + return CALLOC_STRUCT(gl_uniform_list); +} + + +void +_mesa_free_uniform_list(struct gl_uniform_list *list) +{ + GLuint i; + for (i = 0; i < list->NumUniforms; i++) { + _mesa_free((void *) list->Uniforms[i].Name); + } + _mesa_free(list->Uniforms); + _mesa_free(list); +} + + +GLboolean +_mesa_append_uniform(struct gl_uniform_list *list, + const char *name, GLenum target, GLuint progPos) +{ + const GLuint oldNum = list->NumUniforms; + GLint index; + + assert(target == GL_VERTEX_PROGRAM_ARB || + target == GL_FRAGMENT_PROGRAM_ARB); + + index = _mesa_lookup_uniform(list, name); + if (index < 0) { + /* not found - append to list */ + + if (oldNum + 1 > list->Size) { + /* Need to grow the list array (alloc some extra) */ + list->Size += 4; + + /* realloc arrays */ + list->Uniforms = (struct gl_uniform *) + _mesa_realloc(list->Uniforms, + oldNum * sizeof(struct gl_uniform), + list->Size * sizeof(struct gl_uniform)); + } + + if (!list->Uniforms) { + /* out of memory */ + list->NumUniforms = 0; + list->Size = 0; + return GL_FALSE; + } + + list->Uniforms[oldNum].Name = _mesa_strdup(name); + list->Uniforms[oldNum].VertPos = -1; + list->Uniforms[oldNum].FragPos = -1; + index = oldNum; + list->NumUniforms++; + } + + /* update position for the vertex or fragment program */ + if (target == GL_VERTEX_PROGRAM_ARB) { + if (list->Uniforms[index].VertPos != -1) { + /* this uniform is already in the list - that shouldn't happen */ + return GL_FALSE; + } + list->Uniforms[index].VertPos = progPos; + } + else { + if (list->Uniforms[index].FragPos != -1) { + /* this uniform is already in the list - that shouldn't happen */ + return GL_FALSE; + } + list->Uniforms[index].FragPos = progPos; + } + + return GL_TRUE; +} + + +/** + * Return the location/index of the named uniform in the uniform list, + * or -1 if not found. + */ +GLint +_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name) +{ + GLuint i; + for (i = 0; i < list->NumUniforms; i++) { + if (!_mesa_strcmp(list->Uniforms[i].Name, name)) { + return i; + } + } + return -1; +} + + +GLint +_mesa_longest_uniform_name(const struct gl_uniform_list *list) +{ + GLint max = 0; + GLuint i; + for (i = 0; i < list->NumUniforms; i++) { + GLuint len = _mesa_strlen(list->Uniforms[i].Name); + if (len > max) + max = len; + } + return max; +} + + +void +_mesa_print_uniforms(const struct gl_uniform_list *list) +{ + GLuint i; + printf("Uniform list %p:\n", (void *) list); + for (i = 0; i < list->NumUniforms; i++) { + printf("%d: %s %d %d\n", + i, + list->Uniforms[i].Name, + list->Uniforms[i].VertPos, + list->Uniforms[i].FragPos); + } +} diff --git a/src/mesa/shader/prog_uniform.h b/src/mesa/shader/prog_uniform.h new file mode 100644 index 0000000000..735de28705 --- /dev/null +++ b/src/mesa/shader/prog_uniform.h @@ -0,0 +1,91 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_uniform.c + * Shader uniform functions. + * \author Brian Paul + */ + +#ifndef PROG_UNIFORM_H +#define PROG_UNIFORM_H + +#include "main/mtypes.h" +#include "prog_statevars.h" + + +/** + * Shader program uniform variable. + * The glGetUniformLocation() and glUniform() commands will use this + * information. + * Note that a uniform such as "binormal" might be used in both the + * vertex shader and the fragment shader. When glUniform() is called to + * set the uniform's value, it must be updated in both the vertex and + * fragment shaders. The uniform may be in different locations in the + * two shaders so we keep track of that here. + */ +struct gl_uniform +{ + const char *Name; /**< Null-terminated string */ + GLint VertPos; + GLint FragPos; +#if 0 + GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ + GLuint Size; /**< Number of components (1..4) */ +#endif +}; + + +/** + * List of gl_uniforms + */ +struct gl_uniform_list +{ + GLuint Size; /**< allocated size of Uniforms array */ + GLuint NumUniforms; /**< number of uniforms in the array */ + struct gl_uniform *Uniforms; /**< Array [Size] */ +}; + + +extern struct gl_uniform_list * +_mesa_new_uniform_list(void); + +extern void +_mesa_free_uniform_list(struct gl_uniform_list *list); + +extern GLboolean +_mesa_append_uniform(struct gl_uniform_list *list, + const char *name, GLenum target, GLuint progPos); + +extern GLint +_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name); + +extern GLint +_mesa_longest_uniform_name(const struct gl_uniform_list *list); + +extern void +_mesa_print_uniforms(const struct gl_uniform_list *list); + + +#endif /* PROG_UNIFORM_H */ -- cgit v1.2.3 From bc029247d9d886f4546a4c3a36737d09c488b7f9 Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 4 Apr 2008 18:59:21 -0600 Subject: mesa: no longer combine vertex/fragment shader parameters/uniforms GLSL Vertex and fragment shaders now have independent parameter buffers. A new gl_uniform_list is used to keep track of program uniforms and where each uniform is located in each shader's parameter buffer. This makes better use of the space in each buffer and simplifies shader linking. --- src/mesa/main/mtypes.h | 8 +- src/mesa/shader/shader_api.c | 308 ++++++++++++++++++++++--------------- src/mesa/shader/slang/slang_link.c | 192 +++++++---------------- src/mesa/sources | 1 + 4 files changed, 239 insertions(+), 270 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 8e49431a8f..50b22d25bf 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1868,6 +1868,7 @@ enum register_file /** Vertex and fragment instructions */ struct prog_instruction; struct gl_program_parameter_list; +struct gl_uniform_list; /** @@ -2104,7 +2105,7 @@ struct gl_query_state /** - * A GLSL shader object. + * A GLSL vertex or fragment shader object. */ struct gl_shader { @@ -2122,7 +2123,8 @@ struct gl_shader /** - * A GLSL program object. Basically a linked collection of "shaders". + * A GLSL program object. + * Basically a linked collection of vertex and fragment shaders. */ struct gl_shader_program { @@ -2137,7 +2139,7 @@ struct gl_shader_program /* post-link info: */ struct gl_vertex_program *VertexProgram; /**< Linked vertex program */ struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */ - struct gl_program_parameter_list *Uniforms; /**< Plus constants, etc */ + struct gl_uniform_list *Uniforms; struct gl_program_parameter_list *Varying; struct gl_program_parameter_list *Attributes; /**< Vertex attributes */ GLboolean LinkStatus; /**< GL_LINK_STATUS */ diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index 4cb8bb8ed1..9c419c9903 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -43,6 +43,7 @@ #include "prog_parameter.h" #include "prog_print.h" #include "prog_statevars.h" +#include "prog_uniform.h" #include "shader/shader_api.h" #include "shader/slang/slang_compile.h" #include "shader/slang/slang_link.h" @@ -75,25 +76,25 @@ _mesa_clear_shader_program_data(GLcontext *ctx, struct gl_shader_program *shProg) { if (shProg->VertexProgram) { - if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) { - /* to prevent a double-free in the next call */ - shProg->VertexProgram->Base.Parameters = NULL; - } + /* Set ptr to NULL since the param list is shared with the + * original/unlinked program. + */ + shProg->VertexProgram->Base.Parameters = NULL; ctx->Driver.DeleteProgram(ctx, &shProg->VertexProgram->Base); shProg->VertexProgram = NULL; } if (shProg->FragmentProgram) { - if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) { - /* to prevent a double-free in the next call */ - shProg->FragmentProgram->Base.Parameters = NULL; - } + /* Set ptr to NULL since the param list is shared with the + * original/unlinked program. + */ + shProg->FragmentProgram->Base.Parameters = NULL; ctx->Driver.DeleteProgram(ctx, &shProg->FragmentProgram->Base); shProg->FragmentProgram = NULL; } if (shProg->Uniforms) { - _mesa_free_parameter_list(shProg->Uniforms); + _mesa_free_uniform_list(shProg->Uniforms); shProg->Uniforms = NULL; } @@ -673,39 +674,43 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *nameOut) { - struct gl_shader_program *shProg + const struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program); - GLuint ind, j; + const struct gl_program *prog; + GLint progPos; if (!shProg) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform"); return; } - if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) { + if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); return; } - ind = 0; - for (j = 0; j < shProg->Uniforms->NumParameters; j++) { - if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM || - shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) { - if (ind == index) { - /* found it */ - copy_string(nameOut, maxLength, length, - shProg->Uniforms->Parameters[j].Name); - if (size) - *size = shProg->Uniforms->Parameters[j].Size; - if (type) - *type = shProg->Uniforms->Parameters[j].DataType; - return; - } - ind++; + progPos = shProg->Uniforms->Uniforms[index].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[index].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; } } - _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); + if (!prog || progPos < 0) + return; /* should never happen */ + + if (nameOut) + copy_string(nameOut, maxLength, length, + prog->Parameters->Parameters[progPos].Name); + if (size) + *size = prog->Parameters->Parameters[progPos].Size; + + if (type) + *type = prog->Parameters->Parameters[progPos].DataType; } @@ -792,14 +797,10 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program, PROGRAM_INPUT) + 1; break; case GL_ACTIVE_UNIFORMS: - *params - = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM) - + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER); + *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0; break; case GL_ACTIVE_UNIFORM_MAX_LENGTH: - *params = MAX2( - _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM), - _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER)); + *params = _mesa_longest_uniform_name(shProg->Uniforms); if (*params > 0) (*params)++; /* add one for terminating zero */ break; @@ -896,10 +897,23 @@ _mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program); if (shProg) { - GLint i; - if (location >= 0 && location < shProg->Uniforms->NumParameters) { - for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) { - params[i] = shProg->Uniforms->ParameterValues[location][i]; + if (location < shProg->Uniforms->NumUniforms) { + GLint progPos, i; + const struct gl_program *prog; + + progPos = shProg->Uniforms->Uniforms[location].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[location].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; + } + } + + for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) { + params[i] = prog->Parameters->ParameterValues[progPos][i]; } } else { @@ -920,23 +934,10 @@ _mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name) { struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program); - if (shProg) { - GLuint loc; - for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) { - const struct gl_program_parameter *u - = shProg->Uniforms->Parameters + loc; - /* XXX this is a temporary simplification / short-cut. - * We need to handle things like "e.c[0].b" as seen in the - * GLSL orange book, page 189. - */ - if ((u->Type == PROGRAM_UNIFORM || - u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) { - return loc; - } - } - } - return -1; + if (!shProg) + return -1; + return _mesa_lookup_uniform(shProg->Uniforms, name); } @@ -1067,6 +1068,78 @@ update_textures_used(struct gl_program *prog) } +/** + * Set the value of a program's uniform variable. + * \param program the program whose uniform to update + * \param location the location/index of the uniform + * \param type the datatype of the uniform + * \param count the number of uniforms to set + * \param elems number of elements per uniform + * \param values the new values + */ +static void +set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location, + GLenum type, GLint count, GLint elems, const void *values) +{ + if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) { + /* This controls which texture unit which is used by a sampler */ + GLuint texUnit, sampler; + + /* data type for setting samplers must be int */ + if (type != GL_INT || count != 1) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform(only glUniform1i can be used " + "to set sampler uniforms)"); + return; + } + + sampler = (GLuint) program->Parameters->ParameterValues[location][0]; + texUnit = ((GLuint *) values)[0]; + + /* check that the sampler (tex unit index) is legal */ + if (texUnit >= ctx->Const.MaxTextureImageUnits) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glUniform1(invalid sampler/tex unit index)"); + return; + } + + /* This maps a sampler to a texture unit: */ + program->SamplerUnits[sampler] = texUnit; + update_textures_used(program); + + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + } + else { + /* ordinary uniform variable */ + GLint k, i; + + if (count * elems > program->Parameters->Parameters[location].Size) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)"); + return; + } + + for (k = 0; k < count; k++) { + GLfloat *uniformVal = program->Parameters->ParameterValues[location + k]; + if (type == GL_INT || + type == GL_INT_VEC2 || + type == GL_INT_VEC3 || + type == GL_INT_VEC4) { + const GLint *iValues = ((const GLint *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = (GLfloat) iValues[i]; + } + } + else { + const GLfloat *fValues = ((const GLfloat *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = fValues[i]; + } + } + } + } +} + + /** * Called via ctx->Driver.Uniform(). */ @@ -1075,20 +1148,18 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, const GLvoid *values, GLenum type) { struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; - GLint elems, i, k; + GLint elems; if (!shProg || !shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); return; } - if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) { + if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)"); return; } - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)"); return; @@ -1116,63 +1187,54 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, return; } - if (count * elems > shProg->Uniforms->Parameters[location].Size) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)"); - return; - } - - if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) { - /* This controls which texture unit which is used by a sampler */ - GLuint texUnit, sampler; - - /* data type for setting samplers must be int */ - if (type != GL_INT || count != 1) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUniform(only glUniform1i can be used " - "to set sampler uniforms)"); - return; - } - - sampler = (GLuint) shProg->Uniforms->ParameterValues[location][0]; - texUnit = ((GLuint *) values)[0]; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); - /* check that the sampler (tex unit index) is legal */ - if (texUnit >= ctx->Const.MaxTextureImageUnits) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glUniform1(invalid sampler/tex unit index)"); - return; + /* A uniform var may be used by both a vertex shader and a fragment + * shader. We may need to update one or both shader's uniform here: + */ + if (shProg->VertexProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].VertPos; + if (loc >= 0) { + set_program_uniform(ctx, &shProg->VertexProgram->Base, + loc, type, count, elems, values); } + } - if (shProg->VertexProgram) { - shProg->VertexProgram->Base.SamplerUnits[sampler] = texUnit; - update_textures_used(&shProg->VertexProgram->Base); - } - if (shProg->FragmentProgram) { - shProg->FragmentProgram->Base.SamplerUnits[sampler] = texUnit; - update_textures_used(&shProg->FragmentProgram->Base); + if (shProg->FragmentProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].FragPos; + if (loc >= 0) { + set_program_uniform(ctx, &shProg->FragmentProgram->Base, + loc, type, count, elems, values); } + } +} - FLUSH_VERTICES(ctx, _NEW_TEXTURE); +static void +set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program, + GLuint location, GLuint rows, GLuint cols, + GLboolean transpose, const GLfloat *values) +{ + /* + * Note: the _columns_ of a matrix are stored in program registers, not + * the rows. + */ + /* XXXX need to test 3x3 and 2x2 matrices... */ + if (transpose) { + GLuint row, col; + for (col = 0; col < cols; col++) { + GLfloat *v = program->Parameters->ParameterValues[location + col]; + for (row = 0; row < rows; row++) { + v[row] = values[row * cols + col]; + } + } } else { - /* ordinary uniform variable */ - for (k = 0; k < count; k++) { - GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k]; - if (type == GL_INT || - type == GL_INT_VEC2 || - type == GL_INT_VEC3 || - type == GL_INT_VEC4) { - const GLint *iValues = ((const GLint *) values) + k * elems; - for (i = 0; i < elems; i++) { - uniformVal[i] = (GLfloat) iValues[i]; - } - } - else { - const GLfloat *fValues = ((const GLfloat *) values) + k * elems; - for (i = 0; i < elems; i++) { - uniformVal[i] = fValues[i]; - } + GLuint row, col; + for (col = 0; col < cols; col++) { + GLfloat *v = program->Parameters->ParameterValues[location + col]; + for (row = 0; row < rows; row++) { + v[row] = values[col * rows + row]; } } } @@ -1193,7 +1255,7 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, "glUniformMatrix(program not linked)"); return; } - if (location < 0 || location >= shProg->Uniforms->NumParameters) { + if (location < 0 || location >= shProg->Uniforms->NumUniforms) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)"); return; } @@ -1204,27 +1266,19 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, FLUSH_VERTICES(ctx, _NEW_PROGRAM); - /* - * Note: the _columns_ of a matrix are stored in program registers, not - * the rows. - */ - /* XXXX need to test 3x3 and 2x2 matrices... */ - if (transpose) { - GLuint row, col; - for (col = 0; col < cols; col++) { - GLfloat *v = shProg->Uniforms->ParameterValues[location + col]; - for (row = 0; row < rows; row++) { - v[row] = values[row * cols + col]; - } + if (shProg->VertexProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].VertPos; + if (loc >= 0) { + set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base, + loc, rows, cols, transpose, values); } } - else { - GLuint row, col; - for (col = 0; col < cols; col++) { - GLfloat *v = shProg->Uniforms->ParameterValues[location + col]; - for (row = 0; row < rows; row++) { - v[row] = values[col * rows + row]; - } + + if (shProg->FragmentProgram) { + GLint loc = shProg->Uniforms->Uniforms[location].FragPos; + if (loc >= 0) { + set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base, + loc, rows, cols, transpose, values); } } } diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index 390ae56aa5..addff20421 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -37,12 +37,17 @@ #include "shader/prog_parameter.h" #include "shader/prog_print.h" #include "shader/prog_statevars.h" +#include "shader/prog_uniform.h" #include "shader/shader_api.h" #include "slang_link.h" - +/** + * Linking varying vars involves rearranging varying vars so that the + * vertex program's output varyings matches the order of the fragment + * program's input varyings. + */ static GLboolean link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) { @@ -132,148 +137,53 @@ link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) } -static GLboolean -is_uniform(GLuint file) -{ - return (file == PROGRAM_ENV_PARAM || - file == PROGRAM_STATE_VAR || - file == PROGRAM_NAMED_PARAM || - file == PROGRAM_CONSTANT || - file == PROGRAM_SAMPLER || - file == PROGRAM_UNIFORM); -} - - -static GLuint shProg_NumSamplers = 0; /** XXX temporary */ - - -static GLboolean -link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog) +/** + * Build the shProg->Uniforms list. + * This is basically a list/index of all uniforms found in either/both of + * the vertex and fragment shaders. + */ +static void +link_uniform_vars(struct gl_shader_program *shProg, + struct gl_program *prog, + GLuint *numSamplers) { - GLuint *map, i; GLuint samplerMap[MAX_SAMPLERS]; + GLuint i; -#if 0 - printf("================ pre link uniforms ===============\n"); - _mesa_print_parameter_list(shProg->Uniforms); -#endif - - map = (GLuint *) malloc(prog->Parameters->NumParameters * sizeof(GLuint)); - if (!map) - return GL_FALSE; - - for (i = 0; i < prog->Parameters->NumParameters; /* incr below*/) { - /* see if this uniform is in the linked uniform list */ + for (i = 0; i < prog->Parameters->NumParameters; i++) { const struct gl_program_parameter *p = prog->Parameters->Parameters + i; - const GLfloat *pVals = prog->Parameters->ParameterValues[i]; - GLint j; - GLint size; - /* sanity check */ - assert(is_uniform(p->Type)); - - /* See if this uniform is already in the linked program's list */ - if (p->Name) { - /* this is a named uniform */ - j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name); - } - else { - /* this is an unnamed constant */ - /*GLuint swizzle;*/ - ASSERT(p->Type == PROGRAM_CONSTANT); - if (_mesa_lookup_parameter_constant(shProg->Uniforms, pVals, - p->Size, &j, NULL)) { - assert(j >= 0); - } - else { - j = -1; - } - } - - if (j >= 0) { - /* already in linked program's list */ - /* check size XXX check this */ -#if 0 - assert(p->Size == shProg->Uniforms->Parameters[j].Size); -#endif - } - else { - /* not already in linked list */ - switch (p->Type) { - case PROGRAM_ENV_PARAM: - j = _mesa_add_named_parameter(shProg->Uniforms, p->Name, pVals); - break; - case PROGRAM_CONSTANT: - j = _mesa_add_named_constant(shProg->Uniforms, p->Name, pVals, p->Size); - break; - case PROGRAM_STATE_VAR: - j = _mesa_add_state_reference(shProg->Uniforms, p->StateIndexes); - break; - case PROGRAM_UNIFORM: - j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size, p->DataType); - break; - case PROGRAM_SAMPLER: - { - GLuint sampNum = shProg_NumSamplers++; - GLuint oldSampNum; - j = _mesa_add_sampler(shProg->Uniforms, p->Name, - p->DataType, sampNum); - oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0]; - assert(oldSampNum < MAX_SAMPLERS); - samplerMap[oldSampNum] = sampNum; - } - break; - default: - _mesa_problem(NULL, "bad parameter type in link_uniform_vars()"); - return GL_FALSE; - } + /* + * XXX FIX NEEDED HERE + * We should also be adding a uniform if p->Type == PROGRAM_STATE_VAR. + * For example, modelview matrix, light pos, etc. + * Also, we need to update the state-var name-generator code to + * generate GLSL-style names, like "gl_LightSource[0].position". + * Furthermore, we'll need to fix the state-var's size/datatype info. + */ + + if (p->Type == PROGRAM_UNIFORM || + p->Type == PROGRAM_SAMPLER) { + _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i); } - ASSERT(j >= 0); - - size = p->Size; - while (size > 0) { - map[i] = j; - i++; - j++; - size -= 4; + if (p->Type == PROGRAM_SAMPLER) { + /* Allocate a new sampler index */ + GLuint sampNum = *numSamplers; + GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0]; + assert(oldSampNum < MAX_SAMPLERS); + samplerMap[oldSampNum] = sampNum; + (*numSamplers)++; } - } -#if 0 - printf("================ post link uniforms ===============\n"); - _mesa_print_parameter_list(shProg->Uniforms); -#endif - -#if 0 - { - GLuint i; - for (i = 0; i < prog->Parameters->NumParameters; i++) { - printf("map[%d] = %d\n", i, map[i]); - } - _mesa_print_parameter_list(shProg->Uniforms); - } -#endif - /* OK, now scan the program/shader instructions looking for uniform vars, + /* OK, now scan the program/shader instructions looking for sampler vars, * replacing the old index with the new index. */ prog->SamplersUsed = 0x0; for (i = 0; i < prog->NumInstructions; i++) { struct prog_instruction *inst = prog->Instructions + i; - GLuint j; - - if (is_uniform(inst->DstReg.File)) { - inst->DstReg.Index = map[ inst->DstReg.Index ]; - } - - for (j = 0; j < 3; j++) { - if (is_uniform(inst->SrcReg[j].File)) { - inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ]; - } - } - if (_mesa_is_tex_instruction(inst->Opcode)) { /* printf("====== remap sampler from %d to %d\n", @@ -286,9 +196,6 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog) } } - free(map); - - return GL_TRUE; } @@ -476,13 +383,12 @@ _slang_link(GLcontext *ctx, { const struct gl_vertex_program *vertProg; const struct gl_fragment_program *fragProg; + GLuint numSamplers = 0; GLuint i; - shProg_NumSamplers = 0; /** XXX temporary */ - _mesa_clear_shader_program_data(ctx, shProg); - shProg->Uniforms = _mesa_new_parameter_list(); + shProg->Uniforms = _mesa_new_uniform_list(); shProg->Varying = _mesa_new_parameter_list(); /** @@ -519,24 +425,30 @@ _slang_link(GLcontext *ctx, shProg->FragmentProgram = NULL; } + /* link varying vars */ if (shProg->VertexProgram) link_varying_vars(shProg, &shProg->VertexProgram->Base); if (shProg->FragmentProgram) link_varying_vars(shProg, &shProg->FragmentProgram->Base); + /* link uniform vars */ if (shProg->VertexProgram) - link_uniform_vars(shProg, &shProg->VertexProgram->Base); + link_uniform_vars(shProg, &shProg->VertexProgram->Base, &numSamplers); if (shProg->FragmentProgram) - link_uniform_vars(shProg, &shProg->FragmentProgram->Base); + link_uniform_vars(shProg, &shProg->FragmentProgram->Base, &numSamplers); + + /*_mesa_print_uniforms(shProg->Uniforms);*/ - /* The vertex and fragment programs share a common set of uniforms now */ if (shProg->VertexProgram) { - _mesa_free_parameter_list(shProg->VertexProgram->Base.Parameters); - shProg->VertexProgram->Base.Parameters = shProg->Uniforms; + /* Rather than cloning the parameter list here, just share it. + * We need to be careful _mesa_clear_shader_program_data() in + * to avoid double-freeing. + */ + shProg->VertexProgram->Base.Parameters = vertProg->Base.Parameters; } if (shProg->FragmentProgram) { - _mesa_free_parameter_list(shProg->FragmentProgram->Base.Parameters); - shProg->FragmentProgram->Base.Parameters = shProg->Uniforms; + /* see comment just above */ + shProg->FragmentProgram->Base.Parameters = fragProg->Base.Parameters; } if (shProg->VertexProgram) { diff --git a/src/mesa/sources b/src/mesa/sources index d109dce5bc..a4e2026e4b 100644 --- a/src/mesa/sources +++ b/src/mesa/sources @@ -213,6 +213,7 @@ SHADER_SOURCES = \ shader/prog_parameter.c \ shader/prog_print.c \ shader/prog_statevars.c \ + shader/prog_uniform.c \ shader/programopt.c \ shader/shader_api.c \ -- cgit v1.2.3 From f3bd7bf5c913d2a58d424e995b4d441e402bd62b Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 7 Apr 2008 11:15:23 -0600 Subject: mesa: added _mesa_free_instructions() --- src/mesa/shader/prog_instruction.c | 17 +++++++++++++++++ src/mesa/shader/prog_instruction.h | 3 +++ 2 files changed, 20 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c index 066129037a..bea5d0551e 100644 --- a/src/mesa/shader/prog_instruction.c +++ b/src/mesa/shader/prog_instruction.c @@ -118,6 +118,23 @@ _mesa_copy_instructions(struct prog_instruction *dest, } +/** + * Free an array of instructions + */ +void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + for (i = 0; i < count; i++) { + if (inst[i].Data) + _mesa_free(inst[i].Data); + if (inst[i].Comment) + _mesa_free((char *) inst[i].Comment); + } + _mesa_free(inst); +} + + /** * Basic info about each instruction */ diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h index e8a2407ea8..711166f9dd 100644 --- a/src/mesa/shader/prog_instruction.h +++ b/src/mesa/shader/prog_instruction.h @@ -439,6 +439,9 @@ extern struct prog_instruction * _mesa_copy_instructions(struct prog_instruction *dest, const struct prog_instruction *src, GLuint n); +extern void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count); + extern GLuint _mesa_num_inst_src_regs(gl_inst_opcode opcode); -- cgit v1.2.3 From 5d1e73028aabfa1470bfed02c705a2696706f857 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 7 Apr 2008 11:16:18 -0600 Subject: mesa: added _mesa_insert_instructions() Also, use new _mesa_free_instructions() in a few places. --- src/mesa/shader/program.c | 60 +++++++++++++++++++++++++++++++++++++++-------- src/mesa/shader/program.h | 2 ++ 2 files changed, 52 insertions(+), 10 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index 3069b04836..0ed7f833d2 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -287,16 +287,7 @@ _mesa_delete_program(GLcontext *ctx, struct gl_program *prog) if (prog->String) _mesa_free(prog->String); - if (prog->Instructions) { - GLuint i; - for (i = 0; i < prog->NumInstructions; i++) { - if (prog->Instructions[i].Data) - _mesa_free(prog->Instructions[i].Data); - if (prog->Instructions[i].Comment) - _mesa_free((char *) prog->Instructions[i].Comment); - } - _mesa_free(prog->Instructions); - } + _mesa_free_instructions(prog->Instructions, prog->NumInstructions); if (prog->Parameters) { _mesa_free_parameter_list(prog->Parameters); @@ -415,6 +406,55 @@ _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog) } +/** + * Insert 'count' NOP instructions at 'start' in the given program. + * Adjust branch targets accordingly. + */ +GLboolean +_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) +{ + const GLuint origLen = prog->NumInstructions; + const GLuint newLen = origLen + count; + struct prog_instruction *newInst; + GLuint i; + + /* adjust branches */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->BranchTarget > 0) { + if (inst->BranchTarget >= start) { + inst->BranchTarget += count; + } + } + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + return GL_FALSE; + } + + /* Copy 'start' instructions into new instruction buffer */ + _mesa_copy_instructions(newInst, prog->Instructions, start); + + /* init the new instructions */ + _mesa_init_instructions(newInst + start, count); + + /* Copy the remaining/tail instructions to new inst buffer */ + _mesa_copy_instructions(newInst + start + count, + prog->Instructions + start, + origLen - start); + + /* free old instructions */ + _mesa_free_instructions(prog->Instructions, origLen); + + /* install new instructions */ + prog->Instructions = newInst; + prog->NumInstructions = newLen; + + return GL_TRUE; +} + /** * Search instructions for registers that match (oldFile, oldIndex), diff --git a/src/mesa/shader/program.h b/src/mesa/shader/program.h index 4b7297e4c6..414a57d39c 100644 --- a/src/mesa/shader/program.h +++ b/src/mesa/shader/program.h @@ -87,6 +87,8 @@ _mesa_lookup_program(GLcontext *ctx, GLuint id); extern struct gl_program * _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog); +extern GLboolean +_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count); extern struct gl_program * _mesa_combine_programs(GLcontext *ctx, -- cgit v1.2.3 From 48a25bdd3693ec4a2556efb3c387cc3eb8151cb5 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 7 Apr 2008 11:20:21 -0600 Subject: mesa: new _mesa_remove_varying_reads() function We'll apply this function to GLSL vertex programs. In GLSL it's legal to read and write varying (output) vars in a vertex shader. But reading from an output register isn't supported by all hardware. This routine examines the vertex program for that condition and rewrites it to use temporary registers where needed. --- src/mesa/shader/programopt.c | 96 +++++++++++++++++++++++++++++++++++++++++++- src/mesa/shader/programopt.h | 2 + 2 files changed, 96 insertions(+), 2 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c index 9eeb71db1b..7d560c74a5 100644 --- a/src/mesa/shader/programopt.c +++ b/src/mesa/shader/programopt.c @@ -35,6 +35,7 @@ #include "context.h" #include "prog_parameter.h" #include "prog_statevars.h" +#include "program.h" #include "programopt.h" #include "prog_instruction.h" @@ -102,7 +103,7 @@ _mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); /* free old instructions */ - _mesa_free(vprog->Base.Instructions); + _mesa_free_instructions(vprog->Base.Instructions, origLen); /* install new instructions */ vprog->Base.Instructions = newInst; @@ -274,7 +275,7 @@ _mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog) inst++; /* free old instructions */ - _mesa_free(fprog->Base.Instructions); + _mesa_free_instructions(fprog->Base.Instructions, origLen); /* install new instructions */ fprog->Base.Instructions = newInst; @@ -364,3 +365,94 @@ _mesa_count_texture_instructions(struct gl_program *prog) } } + +/** + * Scan/rewrite program to remove reads of varying (output) registers. + * In GLSL vertex shaders, varying vars can be read and written. + * Normally, vertex varying vars are implemented as output registers. + * On some hardware, trying to read an output register causes trouble. + * So, rewrite the program to use a temporary register in this case. + */ +void +_mesa_remove_varying_reads(struct gl_program *prog) +{ + GLuint i; + GLint outputMap[VERT_RESULT_MAX]; + GLuint numVaryingReads = 0; + + assert(prog->Target == GL_VERTEX_PROGRAM_ARB); + + for (i = 0; i < VERT_RESULT_MAX; i++) + outputMap[i] = -1; + + /* look for instructions which read from varying vars */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_VARYING) { + /* replace the read with a temp reg */ + const GLuint var = inst->SrcReg[j].Index; + if (outputMap[var] == -1) { + numVaryingReads++; + outputMap[var] = _mesa_find_free_register(prog, + PROGRAM_TEMPORARY); + } + inst->SrcReg[j].File = PROGRAM_TEMPORARY; + inst->SrcReg[j].Index = outputMap[var]; + } + } + } + + if (numVaryingReads == 0) + return; /* nothing to be done */ + + /* look for instructions which write to the varying vars identified above */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->DstReg.File == PROGRAM_VARYING && + outputMap[inst->DstReg.Index] >= 0) { + /* change inst to write to the temp reg, instead of the varying */ + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = outputMap[inst->DstReg.Index]; + } + } + } + + /* insert new instructions to copy the temp vars to the varying vars */ + { + struct prog_instruction *inst; + GLint endPos, var; + + /* Look for END instruction and insert the new varying writes */ + endPos = -1; + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (inst->Opcode == OPCODE_END) { + endPos = i; + _mesa_insert_instructions(prog, i, numVaryingReads); + break; + } + } + + assert(endPos >= 0); + + /* insert new MOV instructions here */ + inst = prog->Instructions + endPos; + for (var = 0; var < VERT_RESULT_MAX; var++) { + if (outputMap[var] >= 0) { + /* MOV VAR[var], TEMP[tmp]; */ + inst->Opcode = OPCODE_MOV; + inst->DstReg.File = PROGRAM_VARYING; + inst->DstReg.Index = var; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = outputMap[var]; + inst++; + } + } + } +} diff --git a/src/mesa/shader/programopt.h b/src/mesa/shader/programopt.h index ce63644bbf..47ff2f0c7b 100644 --- a/src/mesa/shader/programopt.h +++ b/src/mesa/shader/programopt.h @@ -39,5 +39,7 @@ _mesa_count_texture_indirections(struct gl_program *prog); extern void _mesa_count_texture_instructions(struct gl_program *prog); +extern void +_mesa_remove_varying_reads(struct gl_program *prog); #endif /* PROGRAMOPT_H */ -- cgit v1.2.3 From 42a9218daa8f564ea1b992a48cc3c375fd1b815e Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 7 Apr 2008 11:22:41 -0600 Subject: mesa: call _mesa_remove_varying_reads() after compiling vertex shaders --- src/mesa/shader/slang/slang_compile.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index bfb9ca4db6..0df673085b 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -31,6 +31,8 @@ #include "main/imports.h" #include "main/context.h" #include "shader/program.h" +#include "shader/programopt.h" +#include "shader/prog_print.h" #include "shader/prog_parameter.h" #include "shader/grammar/grammar_mesa.h" #include "slang_codegen.h" @@ -2186,6 +2188,19 @@ _slang_compile(GLcontext *ctx, struct gl_shader *shader) _slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool); ctx->Shader.MemPool = NULL; + if (shader->Type == GL_VERTEX_SHADER) { + /* remove any reads of varying (output) registers */ +#if 0 + printf("Pre-remove output reads:\n"); + _mesa_print_program(shader->Programs[0]); +#endif + _mesa_remove_varying_reads(shader->Programs[0]); +#if 0 + printf("Post-remove output reads:\n"); + _mesa_print_program(shader->Programs[0]); +#endif + } + return success; } -- cgit v1.2.3