summaryrefslogtreecommitdiffstats
path: root/src/mesa
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/shader/nvvertexec.c124
-rw-r--r--src/mesa/shader/nvvertexec.h1
2 files changed, 123 insertions, 2 deletions
diff --git a/src/mesa/shader/nvvertexec.c b/src/mesa/shader/nvvertexec.c
index f8cdfbf17a7..d870f3c1868 100644
--- a/src/mesa/shader/nvvertexec.c
+++ b/src/mesa/shader/nvvertexec.c
@@ -39,6 +39,8 @@
#include "math/m_matrix.h"
+static const GLboolean DEBUG_VERT = GL_FALSE;
+
static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
@@ -67,6 +69,12 @@ _mesa_init_vp_per_vertex_registers(GLcontext *ctx, struct vp_machine *machine)
ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0);
}
}
+
+ /* init condition codes */
+ machine->CondCodes[0] = COND_EQ;
+ machine->CondCodes[1] = COND_EQ;
+ machine->CondCodes[2] = COND_EQ;
+ machine->CondCodes[3] = COND_EQ;
}
@@ -334,6 +342,65 @@ fetch_vector1( GLcontext *ctx,
/**
+ * Test value against zero and return GT, LT, EQ or UN if NaN.
+ */
+static INLINE GLuint
+generate_cc( float value )
+{
+ if (value != value)
+ return COND_UN; /* NaN */
+ if (value > 0.0F)
+ return COND_GT;
+ if (value < 0.0F)
+ return COND_LT;
+ return COND_EQ;
+}
+
+
+/**
+ * Test if the ccMaskRule is satisfied by the given condition code.
+ * Used to mask destination writes according to the current condition code.
+ */
+static INLINE GLboolean
+test_cc(GLuint condCode, GLuint ccMaskRule)
+{
+ switch (ccMaskRule) {
+ case COND_EQ: return (condCode == COND_EQ);
+ case COND_NE: return (condCode != COND_EQ);
+ case COND_LT: return (condCode == COND_LT);
+ case COND_GE: return (condCode == COND_GT || condCode == COND_EQ);
+ case COND_LE: return (condCode == COND_LT || condCode == COND_EQ);
+ case COND_GT: return (condCode == COND_GT);
+ case COND_TR: return GL_TRUE;
+ case COND_FL: return GL_FALSE;
+ default: return GL_TRUE;
+ }
+}
+
+
+/**
+ * Evaluate the 4 condition codes against a predicate and return GL_TRUE
+ * or GL_FALSE to indicate result.
+ */
+static INLINE GLboolean
+eval_condition(const struct vp_machine *machine,
+ const struct prog_instruction *inst)
+{
+ 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)) {
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+
+
+/**
* Store 4 floats into a register.
*/
static void
@@ -342,12 +409,16 @@ store_vector4( const struct prog_instruction *inst,
const GLfloat value[4] )
{
const struct prog_dst_register *dest = &(inst->DstReg);
+ GLuint writeMask = dest->WriteMask;
GLfloat *dst;
+
switch (dest->File) {
case PROGRAM_OUTPUT:
+ ASSERT(dest->Index < VERT_RESULT_MAX);
dst = machine->Outputs[dest->Index];
break;
case PROGRAM_TEMPORARY:
+ ASSERT(dest->Index < MAX_PROGRAM_TEMPS);
dst = machine->Temporaries[dest->Index];
break;
case PROGRAM_ENV_PARAM:
@@ -355,6 +426,7 @@ store_vector4( const struct prog_instruction *inst,
{
/* a slight hack */
GET_CURRENT_CONTEXT(ctx);
+ ASSERT(dest->Index < MAX_PROGRAM_ENV_PARAMS);
dst = ctx->VertexProgram.Parameters[dest->Index];
}
break;
@@ -372,6 +444,17 @@ store_vector4( const struct prog_instruction *inst,
dst[2] = value[2];
if (dest->WriteMask & WRITEMASK_W)
dst[3] = value[3];
+
+ if (inst->CondUpdate) {
+ if (writeMask & WRITEMASK_X)
+ machine->CondCodes[0] = generate_cc(value[0]);
+ if (writeMask & WRITEMASK_Y)
+ machine->CondCodes[1] = generate_cc(value[1]);
+ if (writeMask & WRITEMASK_Z)
+ machine->CondCodes[2] = generate_cc(value[2]);
+ if (writeMask & WRITEMASK_W)
+ machine->CondCodes[3] = generate_cc(value[3]);
+ }
}
@@ -400,7 +483,8 @@ _mesa_exec_vertex_program(GLcontext *ctx,
struct vp_machine *machine,
const struct gl_vertex_program *program)
{
- const struct prog_instruction *inst;
+ const GLuint maxInst = program->Base.NumInstructions;
+ GLuint pc;
ctx->_CurrentProgram = GL_VERTEX_PROGRAM_ARB; /* or NV, doesn't matter */
@@ -416,7 +500,8 @@ _mesa_exec_vertex_program(GLcontext *ctx,
ctx->VertexProgram.Current->Base.OutputsWritten |= VERT_BIT_POS;
}
- for (inst = program->Base.Instructions; ; inst++) {
+ for (pc = 0; pc < maxInst; pc++) {
+ const struct prog_instruction *inst = program->Base.Instructions + pc;
if (ctx->VertexProgram.CallbackEnabled &&
ctx->VertexProgram.Callback) {
@@ -637,6 +722,22 @@ _mesa_exec_vertex_program(GLcontext *ctx,
store_vector4( inst, machine, sge );
}
break;
+ case OPCODE_SGT: /* set on greater */
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4( ctx, &inst->SrcReg[0], machine, program, a );
+ fetch_vector4( ctx, &inst->SrcReg[1], machine, program, b );
+ result[0] = (a[0] > b[0]) ? 1.0F : 0.0F;
+ result[1] = (a[1] > b[1]) ? 1.0F : 0.0F;
+ result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
+ result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
+ store_vector4( inst, machine, result );
+ if (DEBUG_VERT) {
+ printf("SGT %g %g %g %g\n",
+ result[0], result[1], result[2], result[3]);
+ }
+ }
+ break;
case OPCODE_MAD:
{
GLfloat t[4], u[4], v[4], sum[4];
@@ -740,6 +841,25 @@ _mesa_exec_vertex_program(GLcontext *ctx,
store_vector4( inst, machine, t );
}
break;
+ case OPCODE_IF:
+ if (eval_condition(machine, inst)) {
+ /* do if-clause (just continue execution) */
+ }
+ else {
+ /* go to the instruction after ELSE or ENDIF */
+ assert(inst->BranchTarget >= 0);
+ pc = inst->BranchTarget - 1;
+ }
+ break;
+ case OPCODE_ELSE:
+ /* goto ENDIF */
+ assert(inst->BranchTarget >= 0);
+ pc = inst->BranchTarget - 1;
+ break;
+ case OPCODE_ENDIF:
+ /* nothing */
+ break;
+
case OPCODE_EX2: /* GL_ARB_vertex_program */
{
GLfloat t[4];
diff --git a/src/mesa/shader/nvvertexec.h b/src/mesa/shader/nvvertexec.h
index 5516c6b0eab..d7792879736 100644
--- a/src/mesa/shader/nvvertexec.h
+++ b/src/mesa/shader/nvvertexec.h
@@ -39,6 +39,7 @@ struct vp_machine
GLfloat Inputs[VERT_ATTRIB_MAX][4];
GLuint InputsSize[VERT_ATTRIB_MAX];
GLfloat Outputs[VERT_RESULT_MAX][4];
+ GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */
GLint AddressReg[MAX_VERTEX_PROGRAM_ADDRESS_REGS][4];
};