summaryrefslogtreecommitdiffstats
path: root/src/mesa/swrast/s_nvfragprog.c
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2003-01-14 04:57:47 +0000
committerBrian Paul <[email protected]>2003-01-14 04:57:47 +0000
commit890bcc0be3c780ade5d92566d8a79dcffd03281d (patch)
tree84945cc19cb8ef954982f91da4f200bf0b5c7e35 /src/mesa/swrast/s_nvfragprog.c
parent610d59981a9f43fefe29b34ef19c184d28e2bef5 (diff)
fragment program execution
Diffstat (limited to 'src/mesa/swrast/s_nvfragprog.c')
-rw-r--r--src/mesa/swrast/s_nvfragprog.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/mesa/swrast/s_nvfragprog.c b/src/mesa/swrast/s_nvfragprog.c
new file mode 100644
index 00000000000..0980b5dab0b
--- /dev/null
+++ b/src/mesa/swrast/s_nvfragprog.c
@@ -0,0 +1,376 @@
+/* $Id: s_nvfragprog.c,v 1.1 2003/01/14 04:57:47 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.1
+ *
+ * Copyright (C) 1999-2002 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.
+ */
+
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "nvfragprog.h"
+#include "macros.h"
+#include "mmath.h"
+
+#include "s_nvfragprog.h"
+
+
+/**
+ * Fetch a 4-element float vector from the given source register.
+ * Apply swizzling and negating as needed.
+ */
+static void
+fetch_vector4( const struct fp_src_register *source,
+ const struct fp_machine *machine,
+ GLfloat result[4] )
+{
+ const GLfloat *src;
+
+ /*
+ if (source->RelAddr) {
+ GLint reg = source->Register + machine->AddressReg;
+ if (reg < VP_PROG_REG_START || reg > VP_PROG_REG_END)
+ src = zero;
+ else
+ src = machine->Registers[reg];
+ }
+ else
+ */
+
+ src = machine->Registers[source->Register];
+
+ result[0] = src[source->Swizzle[0]];
+ result[1] = src[source->Swizzle[1]];
+ result[2] = src[source->Swizzle[2]];
+ result[3] = src[source->Swizzle[3]];
+
+ if (source->NegateBase) {
+ result[0] = -result[0];
+ result[1] = -result[1];
+ result[2] = -result[2];
+ result[3] = -result[3];
+ }
+ if (source->Abs) {
+ result[0] = FABSF(result[0]);
+ result[1] = FABSF(result[1]);
+ result[2] = FABSF(result[2]);
+ result[3] = FABSF(result[3]);
+ }
+ if (source->NegateAbs) {
+ result[0] = -result[0];
+ result[1] = -result[1];
+ result[2] = -result[2];
+ result[3] = -result[3];
+ }
+}
+
+
+/**
+ * As above, but only return result[0] element.
+ */
+static void
+fetch_vector1( const struct fp_src_register *source,
+ const struct fp_machine *machine,
+ GLfloat result[4] )
+{
+ const GLfloat *src;
+
+ /*
+ if (source->RelAddr) {
+ GLint reg = source->Register + machine->AddressReg;
+ if (reg < VP_PROG_REG_START || reg > VP_PROG_REG_END)
+ src = zero;
+ else
+ src = machine->Registers[reg];
+ }
+ else
+ */
+
+ src = machine->Registers[source->Register];
+
+ result[0] = src[source->Swizzle[0]];
+
+ if (source->NegateBase) {
+ result[0] = -result[0];
+ }
+ if (source->Abs) {
+ result[0] = FABSF(result[0]);
+ }
+ if (source->NegateAbs) {
+ result[0] = -result[0];
+ }
+}
+
+
+/*
+ * 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 codee.
+ */
+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;
+ }
+}
+
+
+/**
+ * Store 4 floats into a register.
+ */
+static void
+store_vector4( const struct fp_dst_register *dest, struct fp_machine *machine,
+ const GLfloat value[4], GLboolean clamp, GLboolean updateCC )
+{
+ GLfloat *dstReg = machine->Registers[dest->Register];
+ GLfloat clampedValue[4];
+ const GLboolean *writeMask = dest->WriteMask;
+ GLboolean condWriteMask[4];
+
+ if (clamp) {
+ clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F);
+ clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F);
+ clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F);
+ clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F);
+ value = clampedValue;
+ }
+
+ if (dest->CondMask != COND_TR) {
+ condWriteMask[0] = writeMask[0]
+ && test_cc(machine->CondCodes[dest->CondSwizzle[0]], dest->CondMask);
+ condWriteMask[1] = writeMask[1]
+ && test_cc(machine->CondCodes[dest->CondSwizzle[1]], dest->CondMask);
+ condWriteMask[2] = writeMask[2]
+ && test_cc(machine->CondCodes[dest->CondSwizzle[2]], dest->CondMask);
+ condWriteMask[3] = writeMask[3]
+ && test_cc(machine->CondCodes[dest->CondSwizzle[3]], dest->CondMask);
+ writeMask = condWriteMask;
+ }
+
+ if (writeMask[0]) {
+ dstReg[0] = value[0];
+ if (updateCC)
+ machine->CondCodes[0] = generate_cc(value[0]);
+ }
+ if (writeMask[1]) {
+ dstReg[1] = value[1];
+ if (updateCC)
+ machine->CondCodes[1] = generate_cc(value[1]);
+ }
+ if (writeMask[2]) {
+ dstReg[2] = value[2];
+ if (updateCC)
+ machine->CondCodes[2] = generate_cc(value[2]);
+ }
+ if (writeMask[3]) {
+ dstReg[3] = value[3];
+ if (updateCC)
+ machine->CondCodes[3] = generate_cc(value[3]);
+ }
+}
+
+
+/**
+ * Execute the given vertex program
+ */
+static void
+execute_program(GLcontext *ctx, const struct fragment_program *program)
+{
+ struct fp_machine *machine = &ctx->FragmentProgram.Machine;
+ const struct fp_instruction *inst;
+
+ for (inst = program->Instructions; inst->Opcode != FP_OPCODE_END; inst++) {
+ switch (inst->Opcode) {
+ case FP_OPCODE_ADD:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4( &inst->SrcReg[0], machine, a );
+ fetch_vector4( &inst->SrcReg[1], machine, b );
+ result[0] = a[0] + b[0];
+ result[1] = a[1] + b[1];
+ result[2] = a[2] + b[2];
+ result[3] = a[3] + b[3];
+ store_vector4( &inst->DstReg, machine, result, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ case FP_OPCODE_COS:
+ {
+ GLfloat a[4], result[4];
+ fetch_vector1( &inst->SrcReg[0], machine, a );
+ result[0] = result[1] = result[2] = result[3] = cos(a[0]);
+ store_vector4( &inst->DstReg, machine, result, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ case FP_OPCODE_DP3:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4( &inst->SrcReg[0], machine, a );
+ fetch_vector4( &inst->SrcReg[1], machine, b );
+ result[0] = result[1] = result[2] = result[3] =
+ a[0] + b[0] + a[1] * b[1] + a[2] * b[2];
+ store_vector4( &inst->DstReg, machine, result, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ case FP_OPCODE_DP4:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4( &inst->SrcReg[0], machine, a );
+ fetch_vector4( &inst->SrcReg[1], machine, b );
+ result[0] = result[1] = result[2] = result[3] =
+ a[0] + b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+ store_vector4( &inst->DstReg, machine, result, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ case FP_OPCODE_KIL:
+ {
+ const GLuint *swizzle = inst->DstReg.CondSwizzle;
+ const GLuint condMask = inst->DstReg.CondMask;
+ if (test_cc(machine->CondCodes[swizzle[0]], condMask) ||
+ test_cc(machine->CondCodes[swizzle[1]], condMask) ||
+ test_cc(machine->CondCodes[swizzle[2]], condMask) ||
+ test_cc(machine->CondCodes[swizzle[3]], condMask))
+ return;
+ }
+ break;
+ case FP_OPCODE_LRP:
+ {
+ GLfloat a[4], b[4], c[4], result[4];
+ fetch_vector4( &inst->SrcReg[0], machine, a );
+ fetch_vector4( &inst->SrcReg[1], machine, b );
+ fetch_vector4( &inst->SrcReg[2], machine, c );
+ result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0];
+ result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1];
+ result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2];
+ result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3];
+ store_vector4( &inst->DstReg, machine, result, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ case FP_OPCODE_MOV:
+ {
+ GLfloat t[4];
+ fetch_vector4( &inst->SrcReg[0], machine, t );
+ store_vector4( &inst->DstReg, machine, t, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ case FP_OPCODE_SEQ:
+ {
+ GLfloat a[4], b[4], result[4];
+ fetch_vector4( &inst->SrcReg[0], machine, a );
+ fetch_vector4( &inst->SrcReg[1], machine, 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->DstReg, machine, result, inst->Saturate,
+ inst->UpdateCondRegister );
+ }
+ break;
+ default:
+ _mesa_problem(ctx, "Bad opcode in _mesa_exec_fragment_program");
+ return;
+ }
+ }
+
+}
+
+
+
+void
+_swrast_exec_nv_fragment_program( GLcontext *ctx, struct sw_span *span )
+{
+ GLuint i;
+
+ for (i = 0; i < span->end; i++) {
+ GLfloat *wpos = ctx->FragmentProgram.Machine.Registers[0];
+ GLfloat *col0 = ctx->FragmentProgram.Machine.Registers[1];
+ GLfloat *col1 = ctx->FragmentProgram.Machine.Registers[2];
+ GLfloat *fogc = ctx->FragmentProgram.Machine.Registers[3];
+ const GLfloat *colOut = ctx->FragmentProgram.Machine.Registers[FP_OUTPUT_REG_START];
+ GLuint j;
+
+ /* Clear temporary registers */
+ for (j = 0; j < MAX_NV_FRAGMENT_PROGRAM_TEMPS; j++) {
+ ctx->FragmentProgram.Machine.Registers[FP_TEMP_REG_START+j][0] = 0.0F;
+ ctx->FragmentProgram.Machine.Registers[FP_TEMP_REG_START+j][1] = 0.0F;
+ ctx->FragmentProgram.Machine.Registers[FP_TEMP_REG_START+j][2] = 0.0F;
+ ctx->FragmentProgram.Machine.Registers[FP_TEMP_REG_START+j][3] = 0.0F;
+ }
+
+ /* Load input registers */
+ wpos[0] = span->x + i;
+ wpos[1] = span->y + i;
+ wpos[2] = span->array->z[i];
+ wpos[3] = 1.0;
+
+ col0[0] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]);
+ col0[1] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]);
+ col0[2] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]);
+ col0[3] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]);
+
+ col1[0] = CHAN_TO_FLOAT(span->array->spec[i][RCOMP]);
+ col1[1] = CHAN_TO_FLOAT(span->array->spec[i][GCOMP]);
+ col1[2] = CHAN_TO_FLOAT(span->array->spec[i][BCOMP]);
+ col1[3] = CHAN_TO_FLOAT(span->array->spec[i][ACOMP]);
+
+ fogc[0] = span->array->fog[i];
+
+ execute_program(ctx, ctx->FragmentProgram.Current);
+
+ /* Store output registers */
+ UNCLAMPED_FLOAT_TO_CHAN(span->array->rgba[i][RCOMP], colOut[0]);
+ UNCLAMPED_FLOAT_TO_CHAN(span->array->rgba[i][GCOMP], colOut[1]);
+ UNCLAMPED_FLOAT_TO_CHAN(span->array->rgba[i][BCOMP], colOut[2]);
+ UNCLAMPED_FLOAT_TO_CHAN(span->array->rgba[i][ACOMP], colOut[3]);
+ }
+}
+