diff options
Diffstat (limited to 'src/mesa/shader')
-rw-r--r-- | src/mesa/shader/arbprogram.c | 9 | ||||
-rw-r--r-- | src/mesa/shader/atifragshader.c | 16 | ||||
-rw-r--r-- | src/mesa/shader/prog_print.c | 41 | ||||
-rw-r--r-- | src/mesa/shader/prog_print.h | 6 | ||||
-rw-r--r-- | src/mesa/shader/prog_statevars.c | 8 | ||||
-rw-r--r-- | src/mesa/shader/program.c | 72 | ||||
-rw-r--r-- | src/mesa/shader/program.h | 8 | ||||
-rw-r--r-- | src/mesa/shader/programopt.c | 11 | ||||
-rw-r--r-- | src/mesa/shader/shader_api.c | 6 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_link.c | 17 |
10 files changed, 151 insertions, 43 deletions
diff --git a/src/mesa/shader/arbprogram.c b/src/mesa/shader/arbprogram.c index 746138071e..7e3040a6ef 100644 --- a/src/mesa/shader/arbprogram.c +++ b/src/mesa/shader/arbprogram.c @@ -489,8 +489,13 @@ _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, return; } - if (ctx->Program.ErrorPos == -1 && ctx->Driver.ProgramStringNotify) - ctx->Driver.ProgramStringNotify( ctx, target, base ); + if (ctx->Program.ErrorPos == -1) { + /* finally, give the program to the driver for translation/checking */ + if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glProgramStringARB(rejected by driver"); + } + } } diff --git a/src/mesa/shader/atifragshader.c b/src/mesa/shader/atifragshader.c index e04a05b22f..ab7b2030d1 100644 --- a/src/mesa/shader/atifragshader.c +++ b/src/mesa/shader/atifragshader.c @@ -378,8 +378,11 @@ _mesa_EndFragmentShaderATI(void) } if (ctx->ATIFragmentShader.Current->cur_pass > 1) ctx->ATIFragmentShader.Current->NumPasses = 2; - else ctx->ATIFragmentShader.Current->NumPasses = 1; - ctx->ATIFragmentShader.Current->cur_pass=0; + else + ctx->ATIFragmentShader.Current->NumPasses = 1; + + ctx->ATIFragmentShader.Current->cur_pass = 0; + #if MESA_DEBUG_ATI_FS for (j = 0; j < MAX_NUM_PASSES_ATI; j++) { for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) { @@ -402,8 +405,13 @@ _mesa_EndFragmentShaderATI(void) } } #endif - if (ctx->Driver.ProgramStringNotify) - ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_SHADER_ATI, NULL ); + + if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) { + ctx->ATIFragmentShader.Current->isValid = GL_FALSE; + /* XXX is this the right error? */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEndFragmentShaderATI(driver rejected shader)"); + } } void GLAPIENTRY diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index 9f9789e010..54fd88ad4f 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -150,6 +150,10 @@ arb_input_attrib_string(GLint index, GLenum progType) "fragment.varying[7]" }; + /* sanity checks */ + assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0); + assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0); + if (progType == GL_VERTEX_PROGRAM_ARB) { assert(index < sizeof(vertAttribs) / sizeof(vertAttribs[0])); return vertAttribs[index]; @@ -162,6 +166,43 @@ arb_input_attrib_string(GLint index, GLenum progType) /** + * Print a vertex program's InputsRead field in human-readable format. + * For debugging. + */ +void +_mesa_print_vp_inputs(GLbitfield inputs) +{ + _mesa_printf("VP Inputs 0x%x: \n", inputs); + while (inputs) { + GLint attr = _mesa_ffs(inputs) - 1; + const char *name = arb_input_attrib_string(attr, + GL_VERTEX_PROGRAM_ARB); + _mesa_printf(" %d: %s\n", attr, name); + inputs &= ~(1 << attr); + } +} + + +/** + * Print a fragment program's InputsRead field in human-readable format. + * For debugging. + */ +void +_mesa_print_fp_inputs(GLbitfield inputs) +{ + _mesa_printf("FP Inputs 0x%x: \n", inputs); + while (inputs) { + GLint attr = _mesa_ffs(inputs) - 1; + const char *name = arb_input_attrib_string(attr, + GL_FRAGMENT_PROGRAM_ARB); + _mesa_printf(" %d: %s\n", attr, name); + inputs &= ~(1 << attr); + } +} + + + +/** * Return ARB_v/f_prog-style output attrib string. */ static const char * diff --git a/src/mesa/shader/prog_print.h b/src/mesa/shader/prog_print.h index fc286ded54..9ab7456016 100644 --- a/src/mesa/shader/prog_print.h +++ b/src/mesa/shader/prog_print.h @@ -37,6 +37,12 @@ typedef enum { } gl_prog_print_mode; +extern void +_mesa_print_vp_inputs(GLbitfield inputs); + +extern void +_mesa_print_fp_inputs(GLbitfield inputs); + extern const char * _mesa_condcode_string(GLuint condcode); diff --git a/src/mesa/shader/prog_statevars.c b/src/mesa/shader/prog_statevars.c index 3a446fd9bb..20321dd01f 100644 --- a/src/mesa/shader/prog_statevars.c +++ b/src/mesa/shader/prog_statevars.c @@ -302,9 +302,11 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[], matrix = &ctx->_ModelProjectMatrix; } else if (mat == STATE_TEXTURE_MATRIX) { + ASSERT(index < Elements(ctx->TextureMatrixStack)); matrix = ctx->TextureMatrixStack[index].Top; } else if (mat == STATE_PROGRAM_MATRIX) { + ASSERT(index < Elements(ctx->ProgramMatrixStack)); matrix = ctx->ProgramMatrixStack[index].Top; } else if (mat == STATE_COLOR_MATRIX) { @@ -1075,7 +1077,9 @@ _mesa_load_tracked_matrices(GLcontext *ctx) mat = ctx->ProjectionMatrixStack.Top; } else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) { - mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top; + GLuint unit = MIN2(ctx->Texture.CurrentUnit, + Elements(ctx->TextureMatrixStack) - 1); + mat = ctx->TextureMatrixStack[unit].Top; } else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) { mat = ctx->ColorMatrixStack.Top; @@ -1087,7 +1091,7 @@ _mesa_load_tracked_matrices(GLcontext *ctx) else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV && ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) { GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV; - ASSERT(n < MAX_PROGRAM_MATRICES); + ASSERT(n < Elements(ctx->ProgramMatrixStack)); mat = ctx->ProgramMatrixStack[n].Top; } else { diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index 3e86d0adad..aaf5f96e2a 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -677,6 +677,8 @@ _mesa_combine_programs(GLcontext *ctx, const GLuint lenB = progB->NumInstructions; const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); const GLuint newLength = lenA + lenB; + GLboolean usedTemps[MAX_PROGRAM_TEMPS]; + GLuint firstTemp = 0; GLbitfield inputsB; GLuint i; @@ -698,6 +700,10 @@ _mesa_combine_programs(GLcontext *ctx, newProg->Instructions = newInst; newProg->NumInstructions = newLength; + /* find used temp regs (we may need new temps below) */ + _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, + usedTemps, MAX_PROGRAM_TEMPS); + if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { struct gl_fragment_program *fprogA, *fprogB, *newFprog; GLbitfield progB_inputsRead = progB->InputsRead; @@ -741,12 +747,15 @@ _mesa_combine_programs(GLcontext *ctx, */ if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) && (progB_inputsRead & FRAG_BIT_COL0)) { - GLint tempReg = _mesa_find_free_register(newProg, PROGRAM_TEMPORARY); + GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, + firstTemp); if (tempReg < 0) { _mesa_problem(ctx, "No free temp regs found in " "_mesa_combine_programs(), using 31"); tempReg = 31; } + firstTemp = tempReg + 1; + /* replace writes to result.color[0] with tempReg */ replace_registers(newInst, lenA, PROGRAM_OUTPUT, FRAG_RESULT_COLOR, @@ -784,53 +793,64 @@ _mesa_combine_programs(GLcontext *ctx, } - - /** - * Scan the given program to find a free register of the given type. - * \param regFile - PROGRAM_INPUT, PROGRAM_OUTPUT or PROGRAM_TEMPORARY + * Populate the 'used' array with flags indicating which registers (TEMPs, + * INPUTs, OUTPUTs, etc, are used by the given program. + * \param file type of register to scan for + * \param used returns true/false flags for in use / free + * \param usedSize size of the 'used' array */ -GLint -_mesa_find_free_register(const struct gl_program *prog, GLuint regFile) +void +_mesa_find_used_registers(const struct gl_program *prog, + gl_register_file file, + GLboolean used[], GLuint usedSize) { - GLboolean used[MAX_PROGRAM_TEMPS]; - GLuint i, k; - - assert(regFile == PROGRAM_INPUT || - regFile == PROGRAM_OUTPUT || - regFile == PROGRAM_TEMPORARY); + GLuint i, j; - _mesa_memset(used, 0, sizeof(used)); + _mesa_memset(used, 0, usedSize); for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); - /* check dst reg first */ - if (inst->DstReg.File == regFile) { + if (inst->DstReg.File == file) { used[inst->DstReg.Index] = GL_TRUE; } - else { - /* check src regs otherwise */ - for (k = 0; k < n; k++) { - if (inst->SrcReg[k].File == regFile) { - used[inst->SrcReg[k].Index] = GL_TRUE; - break; - } + + for (j = 0; j < n; j++) { + if (inst->SrcReg[j].File == file) { + used[inst->SrcReg[j].Index] = GL_TRUE; } } } +} - for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + +/** + * Scan the given 'used' register flag array for the first entry + * that's >= firstReg. + * \param used vector of flags indicating registers in use (as returned + * by _mesa_find_used_registers()) + * \param usedSize size of the 'used' array + * \param firstReg first register to start searching at + * \return index of unused register, or -1 if none. + */ +GLint +_mesa_find_free_register(const GLboolean used[], + GLuint usedSize, GLuint firstReg) +{ + GLuint i; + + assert(firstReg < usedSize); + + for (i = firstReg; i < usedSize; i++) if (!used[i]) return i; - } return -1; } - /** * "Post-process" a GPU program. This is intended to be used for debugging. * Example actions include no-op'ing instructions or changing instruction diff --git a/src/mesa/shader/program.h b/src/mesa/shader/program.h index 56a4191f57..0187a2c55f 100644 --- a/src/mesa/shader/program.h +++ b/src/mesa/shader/program.h @@ -119,8 +119,14 @@ _mesa_combine_programs(GLcontext *ctx, const struct gl_program *progA, const struct gl_program *progB); +extern void +_mesa_find_used_registers(const struct gl_program *prog, + gl_register_file file, + GLboolean used[], GLuint usedSize); + extern GLint -_mesa_find_free_register(const struct gl_program *prog, GLuint regFile); +_mesa_find_free_register(const GLboolean used[], + GLuint maxRegs, GLuint firstReg); extern void _mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog); diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c index 9514545709..fb2ebe6338 100644 --- a/src/mesa/shader/programopt.c +++ b/src/mesa/shader/programopt.c @@ -495,6 +495,11 @@ _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) GLuint i; GLint outputMap[VERT_RESULT_MAX]; GLuint numVaryingReads = 0; + GLboolean usedTemps[MAX_PROGRAM_TEMPS]; + GLuint firstTemp = 0; + + _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, + usedTemps, MAX_PROGRAM_TEMPS); assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT); assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING); @@ -513,8 +518,10 @@ _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) const GLuint var = inst->SrcReg[j].Index; if (outputMap[var] == -1) { numVaryingReads++; - outputMap[var] = _mesa_find_free_register(prog, - PROGRAM_TEMPORARY); + outputMap[var] = _mesa_find_free_register(usedTemps, + MAX_PROGRAM_TEMPS, + firstTemp); + firstTemp = outputMap[var] + 1; } inst->SrcReg[j].File = PROGRAM_TEMPORARY; inst->SrcReg[j].Index = outputMap[var]; diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index d53580f5f6..e8eaa9c103 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -1715,7 +1715,11 @@ set_program_uniform(GLcontext *ctx, struct gl_program *program, */ FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); _mesa_update_shader_textures_used(program); - ctx->Driver.ProgramStringNotify(ctx, program->Target, program); + /* Do we need to care about the return value here? + * This should not be the first time the driver was notified of + * this program. + */ + (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program); } } else { diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index 21497b34e2..df524ce078 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -719,6 +719,7 @@ _slang_link(GLcontext *ctx, { const struct gl_vertex_program *vertProg = NULL; const struct gl_fragment_program *fragProg = NULL; + GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE; GLuint numSamplers = 0; GLuint i; @@ -871,8 +872,8 @@ _slang_link(GLcontext *ctx, _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); /* notify driver that a new fragment program has been compiled/linked */ - ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, - &shProg->FragmentProgram->Base); + vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, + &shProg->FragmentProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { _mesa_printf("Mesa pre-link fragment program:\n"); _mesa_print_program(&fragProg->Base); @@ -889,8 +890,8 @@ _slang_link(GLcontext *ctx, _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); /* notify driver that a new vertex program has been compiled/linked */ - ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, - &shProg->VertexProgram->Base); + fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, + &shProg->VertexProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { _mesa_printf("Mesa pre-link vertex program:\n"); _mesa_print_program(&vertProg->Base); @@ -918,6 +919,12 @@ _slang_link(GLcontext *ctx, } } - shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); + if (!vertNotify || !fragNotify) { + /* driver rejected one/both of the vertex/fragment programs */ + link_error(shProg, "Vertex and/or fragment program rejected by driver\n"); + } + else { + shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); + } } |