summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mesa/main/config.h1
-rw-r--r--src/mesa/shader/program_instruction.h7
-rw-r--r--src/mesa/swrast/s_nvfragprog.c53
3 files changed, 60 insertions, 1 deletions
diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h
index 5a0481328ff..13c6281f077 100644
--- a/src/mesa/main/config.h
+++ b/src/mesa/main/config.h
@@ -198,6 +198,7 @@
#define MAX_PROGRAM_LOCAL_PARAMS 128 /* KW: power of two */
#define MAX_PROGRAM_MATRICES 8
#define MAX_PROGRAM_MATRIX_STACK_DEPTH 4
+#define MAX_PROGRAM_CALL_DEPTH 8
/*@}*/
/** For GL_ARB_fragment_shader */
diff --git a/src/mesa/shader/program_instruction.h b/src/mesa/shader/program_instruction.h
index cdec0ceb2a5..ad3a6d4dd4e 100644
--- a/src/mesa/shader/program_instruction.h
+++ b/src/mesa/shader/program_instruction.h
@@ -286,7 +286,7 @@ struct prog_instruction
GLuint CondUpdate:1;
/**
- * If prog_instruction::cc_update is \c GL_TRUE, this value selects the
+ * If prog_instruction::CondUpdate is \c GL_TRUE, this value selects the
* condition code register that is to be updated.
*
* In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition
@@ -339,6 +339,11 @@ struct prog_instruction
*/
GLuint TexSrcTarget:3;
/*@}*/
+
+ /**
+ * For BRA and CAL instructions, the location to jump to.
+ */
+ GLuint BranchTarget;
};
diff --git a/src/mesa/swrast/s_nvfragprog.c b/src/mesa/swrast/s_nvfragprog.c
index 7a6785b1d29..028ddc0090d 100644
--- a/src/mesa/swrast/s_nvfragprog.c
+++ b/src/mesa/swrast/s_nvfragprog.c
@@ -57,6 +57,9 @@ struct fp_machine
GLfloat Inputs[MAX_NV_FRAGMENT_PROGRAM_INPUTS][4];
GLfloat Outputs[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS][4];
GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */
+
+ GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */
+ GLuint StackDepth; /**< Index/ptr to top of CallStack[] */
};
@@ -697,6 +700,37 @@ execute_program( GLcontext *ctx,
}
}
break;
+ case OPCODE_BRA: /* conditional branch */
+ {
+ /* NOTE: The return is conditional! */
+ const GLuint swizzle = inst->DstReg.CondSwizzle;
+ const GLuint condMask = inst->DstReg.CondMask;
+ if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
+ /* take branch */
+ pc = inst->BranchTarget;
+ }
+ }
+ break;
+ case OPCODE_CAL: /* Call subroutine */
+ {
+ /* NOTE: The call is conditional! */
+ const GLuint swizzle = inst->DstReg.CondSwizzle;
+ const GLuint condMask = inst->DstReg.CondMask;
+ if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
+ if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) {
+ return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
+ }
+ machine->CallStack[machine->StackDepth++] = pc + 1;
+ pc = inst->BranchTarget;
+ }
+ }
+ break;
case OPCODE_CMP:
{
GLfloat a[4], b[4], c[4], result[4];
@@ -1093,6 +1127,22 @@ execute_program( GLcontext *ctx,
store_vector4( inst, machine, result );
}
break;
+ case OPCODE_RET: /* return from subroutine */
+ {
+ /* NOTE: The return is conditional! */
+ const GLuint swizzle = inst->DstReg.CondSwizzle;
+ const GLuint condMask = inst->DstReg.CondMask;
+ if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
+ test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
+ if (machine->StackDepth == 0) {
+ return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
+ }
+ pc = machine->CallStack[--machine->StackDepth];
+ }
+ }
+ break;
case OPCODE_RFL: /* reflection vector */
{
GLfloat axis[4], dir[4], result[4], tmpX, tmpW;
@@ -1539,6 +1589,9 @@ init_machine( GLcontext *ctx, struct fp_machine *machine,
machine->CondCodes[1] = COND_EQ;
machine->CondCodes[2] = COND_EQ;
machine->CondCodes[3] = COND_EQ;
+
+ /* init call stack */
+ machine->StackDepth = 0;
}