fragment.position support
authorRune Petersen <rune@megahurts.dk>
Fri, 17 Nov 2006 19:12:42 +0000 (19:12 +0000)
committerRune Petersen <rune@megahurts.dk>
Fri, 17 Nov 2006 19:12:42 +0000 (19:12 +0000)
World position is calculated in the vertex shader and passed to the
fragment shader via an unused texcoord.

src/mesa/drivers/dri/r300/r300_context.h
src/mesa/drivers/dri/r300/r300_fragprog.c
src/mesa/drivers/dri/r300/r300_state.c
src/mesa/drivers/dri/r300/r300_vertexprog.c

index 2c8120e..dd3ecbb 100644 (file)
@@ -549,6 +549,7 @@ struct r300_stencilbuffer_state {
 /* Can be tested with colormat currently. */
 #define VSF_MAX_FRAGMENT_TEMPS (14)
 
+#define STATE_R300_WINDOW_DIMENSION (STATE_INTERNAL_DRIVER+0)
 
 struct r300_vertex_shader_fragment {
        int length;
@@ -623,6 +624,7 @@ struct r300_vertex_program {
        
        int pos_end;
        int num_temporaries; /* Number of temp vars used by program */
+       int wpos_idx;
        int inputs[VERT_ATTRIB_MAX];
        int outputs[VERT_RESULT_MAX];
        int native;
index 7793c5e..cab5451 100644 (file)
@@ -1555,6 +1555,13 @@ static void init_program(struct r300_fragment_program *rp)
        }
        InputsRead &= ~FRAG_BITS_TEX_ANY;
 
+       /* fragment position treated as a texcoord */
+       if (InputsRead & FRAG_BIT_WPOS) {
+               cs->inputs[FRAG_ATTRIB_WPOS].refcount = 0;
+               cs->inputs[FRAG_ATTRIB_WPOS].reg = get_hw_temp(rp);
+       }
+       InputsRead &= ~FRAG_BIT_WPOS;
+
        /* Then primary colour */
        if (InputsRead & FRAG_BIT_COL0) {
                cs->inputs[FRAG_ATTRIB_COL0].refcount = 0;
index aa49f05..7225506 100644 (file)
@@ -1044,6 +1044,59 @@ r300UpdateDrawBuffer(GLcontext *ctx)
 #endif
 }
 
+static void r300FetchStateParameter(GLcontext *ctx, const enum state_index state[],
+                  GLfloat *value)
+{
+    r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+    switch(state[0])
+    {
+    case STATE_INTERNAL:
+       switch(state[1])
+       {
+       case STATE_R300_WINDOW_DIMENSION:
+           value[0] = r300->radeon.dri.drawable->w;    /* width */
+           value[1] = r300->radeon.dri.drawable->h;    /* height */
+           value[2] = 0.5F;                            /* for moving range [-1 1] -> [0 1] */
+           value[3] = 1.0F;                            /* not used */
+           break;
+       default:;
+       }
+    default:;
+    }
+}
+
+/**
+ * Update R300's own internal state parameters.
+ * For now just STATE_R300_WINDOW_DIMENSION
+ */
+static void r300UpdateStateParameters(GLcontext * ctx, GLuint new_state)
+{
+       struct r300_vertex_program_cont *vpc;
+       struct gl_program_parameter_list *paramList;
+       GLuint i;
+
+       if(!(new_state & (_NEW_BUFFERS|_NEW_PROGRAM)))
+           return;
+
+       vpc = (struct r300_vertex_program_cont *)ctx->VertexProgram._Current;
+       if (!vpc)
+           return;
+
+       paramList = vpc->mesa_program.Base.Parameters;
+
+       if (!paramList)
+           return;
+
+       for (i = 0; i < paramList->NumParameters; i++) {
+               if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR){
+                       r300FetchStateParameter(ctx,
+                                   paramList->Parameters[i].StateIndexes,
+                                   paramList->ParameterValues[i]);
+               }
+       }
+}
+
 /* =============================================================
  * Polygon state
  */
@@ -1304,6 +1357,20 @@ void r300_setup_rs_unit(GLcontext *ctx)
 
        r300->hw.rr.cmd[R300_RR_ROUTE_1] = 0;
        
+       if (InputsRead & FRAG_BIT_WPOS){
+               for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
+                       if (!(InputsRead & (FRAG_BIT_TEX0 << i)))
+                               break;
+
+               if(i == ctx->Const.MaxTextureUnits){
+                       fprintf(stderr, "\tno free texcoord found...\n");
+                       exit(0);
+               }
+
+               InputsRead |= (FRAG_BIT_TEX0 << i);
+               InputsRead &= ~FRAG_BIT_WPOS;
+       }
+       
        for (i=0;i<ctx->Const.MaxTextureUnits;i++) {
                r300->hw.ri.cmd[R300_RI_INTERP_0+i] = 0
                                | R300_RS_INTERP_USED
@@ -1680,6 +1747,7 @@ void r300UpdateShaders(r300ContextPtr rmesa)
 
                        return ;
                }
+               r300UpdateStateParameters(ctx, _NEW_PROGRAM);
        }
        
 }
@@ -1813,6 +1881,9 @@ static void r300InvalidateState(GLcontext * ctx, GLuint new_state)
        if (new_state & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) {
                r300UpdateDrawBuffer(ctx);
        }
+
+       r300UpdateStateParameters(ctx, new_state);
+
 #ifndef CB_DPATH
        /* Go inefficiency! */
        r300ResetHwState(r300);
index c38db7e..2492a4a 100644 (file)
@@ -958,17 +958,155 @@ static void position_invariant(struct gl_program *prog)
        assert(vpi->Opcode == OPCODE_END);
 }
 
+static void insert_wpos(struct r300_vertex_program *vp,
+                      struct gl_program *prog,
+                      GLint pos)
+{
+
+       GLint tokens[6] = { STATE_INTERNAL, STATE_R300_WINDOW_DIMENSION, 0, 0, 0, 0 };
+       struct prog_instruction *vpi;
+       struct prog_instruction *vpi_insert;
+       GLuint temp_index;
+       GLuint window_index;
+       int i = 0;
+       
+       vpi = malloc((prog->NumInstructions + 5) * sizeof(struct prog_instruction));
+       memcpy(vpi, prog->Instructions, (pos+1) * sizeof(struct prog_instruction));
+       
+       vpi_insert = &vpi[pos];
+
+       /* make a copy before outputting VERT_RESULT_HPOS */
+       vpi_insert->DstReg.File = vpi_insert->SrcReg[2].File;
+       vpi_insert->DstReg.Index = temp_index = vpi_insert->SrcReg[2].Index;
+       
+       vpi_insert++;
+       memset(vpi_insert, 0, 5 * sizeof(struct prog_instruction));
+
+       vpi_insert[i].Opcode = OPCODE_MOV;
+
+       vpi_insert[i].DstReg.File = PROGRAM_OUTPUT;
+       vpi_insert[i].DstReg.Index = VERT_RESULT_HPOS;
+       vpi_insert[i].DstReg.WriteMask = WRITEMASK_XYZW;
+       vpi_insert[i].DstReg.CondMask = COND_TR;
+
+       vpi_insert[i].SrcReg[0].File = PROGRAM_TEMPORARY;
+       vpi_insert[i].SrcReg[0].Index = temp_index;
+       vpi_insert[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W);
+       i++;
+
+       /* perspective divide */
+       vpi_insert[i].Opcode = OPCODE_RCP;
+
+       vpi_insert[i].DstReg.File = PROGRAM_TEMPORARY;
+       vpi_insert[i].DstReg.Index = temp_index;
+       vpi_insert[i].DstReg.WriteMask = WRITEMASK_W;
+       vpi_insert[i].DstReg.CondMask = COND_TR;
+
+       vpi_insert[i].SrcReg[0].File = PROGRAM_TEMPORARY;
+       vpi_insert[i].SrcReg[0].Index = temp_index;
+       vpi_insert[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO);
+       i++;
+
+       vpi_insert[i].Opcode = OPCODE_MUL;
+
+       vpi_insert[i].DstReg.File = PROGRAM_TEMPORARY;
+       vpi_insert[i].DstReg.Index = temp_index;
+       vpi_insert[i].DstReg.WriteMask = WRITEMASK_XYZ;
+       vpi_insert[i].DstReg.CondMask = COND_TR;
+
+       vpi_insert[i].SrcReg[0].File = PROGRAM_TEMPORARY;
+       vpi_insert[i].SrcReg[0].Index = temp_index;
+       vpi_insert[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);
+
+       vpi_insert[i].SrcReg[1].File = PROGRAM_TEMPORARY;
+       vpi_insert[i].SrcReg[1].Index = temp_index;
+       vpi_insert[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_ZERO);
+       i++;
+
+       /* viewport transformation */
+       window_index = _mesa_add_state_reference(prog->Parameters, tokens);
+
+       vpi_insert[i].Opcode = OPCODE_MAD;
+
+       vpi_insert[i].DstReg.File = PROGRAM_TEMPORARY;
+       vpi_insert[i].DstReg.Index = temp_index;
+       vpi_insert[i].DstReg.WriteMask = WRITEMASK_XYZ;
+       vpi_insert[i].DstReg.CondMask = COND_TR;
+
+       vpi_insert[i].SrcReg[0].File = PROGRAM_TEMPORARY;
+       vpi_insert[i].SrcReg[0].Index = temp_index;
+       vpi_insert[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);
+
+       vpi_insert[i].SrcReg[1].File = PROGRAM_STATE_VAR;
+       vpi_insert[i].SrcReg[1].Index = window_index;
+       vpi_insert[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_ZERO);
+
+       vpi_insert[i].SrcReg[2].File = PROGRAM_STATE_VAR;
+       vpi_insert[i].SrcReg[2].Index = window_index;
+       vpi_insert[i].SrcReg[2].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_ZERO);
+       i++;
+
+       vpi_insert[i].Opcode = OPCODE_MUL;
+
+       vpi_insert[i].DstReg.File = PROGRAM_OUTPUT;
+       vpi_insert[i].DstReg.Index = VERT_RESULT_TEX0+vp->wpos_idx;
+       vpi_insert[i].DstReg.WriteMask = WRITEMASK_XYZW;
+       vpi_insert[i].DstReg.CondMask = COND_TR;
+
+       vpi_insert[i].SrcReg[0].File = PROGRAM_TEMPORARY;
+       vpi_insert[i].SrcReg[0].Index = temp_index;
+       vpi_insert[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W);
+
+       vpi_insert[i].SrcReg[1].File = PROGRAM_STATE_VAR;
+       vpi_insert[i].SrcReg[1].Index = window_index;
+       vpi_insert[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_ONE, SWIZZLE_ONE);
+       i++;
+
+       memcpy(&vpi_insert[i], &prog->Instructions[pos+1], (prog->NumInstructions-(pos+1)) * sizeof(struct prog_instruction));
+
+       free(prog->Instructions);
+
+       prog->Instructions = vpi;
+
+       prog->NumInstructions += i;
+       vpi = &prog->Instructions[prog->NumInstructions-1];
+
+       assert(vpi->Opcode == OPCODE_END);
+}
+
+static void pos_as_texcoord(struct r300_vertex_program *vp,
+                           struct gl_program *prog)
+{
+       struct prog_instruction *vpi;
+       int pos = 0;
+       
+       for(vpi = prog->Instructions; vpi->Opcode != OPCODE_END; vpi++, pos++){
+               if( vpi->DstReg.File == PROGRAM_OUTPUT &&
+                   vpi->DstReg.Index == VERT_RESULT_HPOS ){
+                       insert_wpos(vp, prog, pos);
+                       break;
+               }
+       }
+
+}
+
 static struct r300_vertex_program *build_program(struct r300_vertex_program_key *wanted_key,
-                                                struct gl_vertex_program *mesa_vp)
+                                                struct gl_vertex_program *mesa_vp,
+                                                GLint wpos_idx)
 {
        struct r300_vertex_program *vp;
 
        vp = _mesa_calloc(sizeof(*vp));
        _mesa_memcpy(&vp->key, wanted_key, sizeof(vp->key));
 
+       vp->wpos_idx = wpos_idx;
+
        if(mesa_vp->IsPositionInvariant)
                position_invariant(&mesa_vp->Base);
 
+       if(wpos_idx > -1)
+               pos_as_texcoord(vp, &mesa_vp->Base);
+
        assert(mesa_vp->Base.NumInstructions);
 
        vp->num_temporaries=mesa_vp->Base.NumTemporaries;
@@ -986,12 +1124,28 @@ void r300_select_vertex_shader(r300ContextPtr r300)
        GLint i;
        struct r300_vertex_program_cont *vpc;
        struct r300_vertex_program *vp;
+       GLint wpos_idx;
 
        vpc = (struct r300_vertex_program_cont *)ctx->VertexProgram._Current;
        InputsRead = ctx->FragmentProgram._Current->Base.InputsRead;
 
        wanted_key.OutputsWritten |= 1 << VERT_RESULT_HPOS;
 
+       wpos_idx = -1;
+       if (InputsRead & FRAG_BIT_WPOS){
+               for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
+                       if (!(InputsRead & (FRAG_BIT_TEX0 << i)))
+                               break;
+               
+               if(i == ctx->Const.MaxTextureUnits){
+                       fprintf(stderr, "\tno free texcoord found\n");
+                       exit(0);
+               }
+
+               InputsRead |= (FRAG_BIT_TEX0 << i);
+               wpos_idx = i;
+       }
+
        if (InputsRead & FRAG_BIT_COL0)
                wanted_key.OutputsWritten |= 1 << VERT_RESULT_COL0;
 
@@ -1013,7 +1167,7 @@ void r300_select_vertex_shader(r300ContextPtr r300)
 
        //_mesa_print_program(&vpc->mesa_program.Base);
 
-       vp = build_program(&wanted_key, &vpc->mesa_program);
+       vp = build_program(&wanted_key, &vpc->mesa_program, wpos_idx);
        vp->next = vpc->progs;
        vpc->progs = vp;