summaryrefslogtreecommitdiff
path: root/src/mesa/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/shader')
-rw-r--r--src/mesa/shader/arbprogram.c9
-rw-r--r--src/mesa/shader/atifragshader.c16
-rw-r--r--src/mesa/shader/prog_print.c41
-rw-r--r--src/mesa/shader/prog_print.h6
-rw-r--r--src/mesa/shader/prog_statevars.c8
-rw-r--r--src/mesa/shader/program.c72
-rw-r--r--src/mesa/shader/program.h8
-rw-r--r--src/mesa/shader/programopt.c11
-rw-r--r--src/mesa/shader/shader_api.c6
-rw-r--r--src/mesa/shader/slang/slang_link.c17
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);
+ }
}