Make sure we use only signed/unsigned ints with bitfields.
[mesa.git] / src / mesa / drivers / dri / r300 / r300_vertprog.c
index 7dcf7d03837e8b41b0c6a4815ddbdc823c647628..aa98a049aa4aad5d64ab00c5997263a3200c6f25 100644 (file)
@@ -41,8 +41,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "tnl/tnl.h"
 
 #include "compiler/radeon_compiler.h"
-#include "compiler/radeon_nqssadce.h"
+#include "radeon_mesa_to_rc.h"
 #include "r300_context.h"
+#include "r300_fragprog_common.h"
 #include "r300_state.h"
 
 /**
@@ -61,12 +62,6 @@ static int r300VertexProgUpdateParams(GLcontext * ctx, struct r300_vertex_progra
                }
        }
 
-       if (vp->code.constants.Count * 4 > VSF_MAX_FRAGMENT_LENGTH) {
-               /* Should have checked this earlier... */
-               fprintf(stderr, "%s:Params exhausted\n", __FUNCTION__);
-               _mesa_exit(-1);
-       }
-
        for(i = 0; i < vp->code.constants.Count; ++i) {
                const float * src = 0;
                const struct rc_constant * constant = &vp->code.constants.Constants[i];
@@ -128,6 +123,110 @@ static GLbitfield compute_required_outputs(struct gl_vertex_program * vp, GLbitf
        return outputs;
 }
 
+
+static void t_inputs_outputs(struct r300_vertex_program_compiler * c)
+{
+       int i;
+       int cur_reg;
+       GLuint OutputsWritten, InputsRead;
+
+       OutputsWritten = c->Base.Program.OutputsWritten;
+       InputsRead = c->Base.Program.InputsRead;
+
+       cur_reg = -1;
+       for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+               if (InputsRead & (1 << i))
+                       c->code->inputs[i] = ++cur_reg;
+               else
+                       c->code->inputs[i] = -1;
+       }
+
+       cur_reg = 0;
+       for (i = 0; i < VERT_RESULT_MAX; i++)
+               c->code->outputs[i] = -1;
+
+       assert(OutputsWritten & (1 << VERT_RESULT_HPOS));
+
+       if (OutputsWritten & (1 << VERT_RESULT_HPOS)) {
+               c->code->outputs[VERT_RESULT_HPOS] = cur_reg++;
+       }
+
+       if (OutputsWritten & (1 << VERT_RESULT_PSIZ)) {
+               c->code->outputs[VERT_RESULT_PSIZ] = cur_reg++;
+       }
+
+       /* If we're writing back facing colors we need to send
+        * four colors to make front/back face colors selection work.
+        * If the vertex program doesn't write all 4 colors, lets
+        * pretend it does by skipping output index reg so the colors
+        * get written into appropriate output vectors.
+        */
+       if (OutputsWritten & (1 << VERT_RESULT_COL0)) {
+               c->code->outputs[VERT_RESULT_COL0] = cur_reg++;
+       } else if (OutputsWritten & (1 << VERT_RESULT_BFC0) ||
+               OutputsWritten & (1 << VERT_RESULT_BFC1)) {
+               cur_reg++;
+       }
+
+       if (OutputsWritten & (1 << VERT_RESULT_COL1)) {
+               c->code->outputs[VERT_RESULT_COL1] = cur_reg++;
+       } else if (OutputsWritten & (1 << VERT_RESULT_BFC0) ||
+               OutputsWritten & (1 << VERT_RESULT_BFC1)) {
+               cur_reg++;
+       }
+
+       if (OutputsWritten & (1 << VERT_RESULT_BFC0)) {
+               c->code->outputs[VERT_RESULT_BFC0] = cur_reg++;
+       } else if (OutputsWritten & (1 << VERT_RESULT_BFC1)) {
+               cur_reg++;
+       }
+
+       if (OutputsWritten & (1 << VERT_RESULT_BFC1)) {
+               c->code->outputs[VERT_RESULT_BFC1] = cur_reg++;
+       } else if (OutputsWritten & (1 << VERT_RESULT_BFC0)) {
+               cur_reg++;
+       }
+
+       for (i = VERT_RESULT_TEX0; i <= VERT_RESULT_TEX7; i++) {
+               if (OutputsWritten & (1 << i)) {
+                       c->code->outputs[i] = cur_reg++;
+               }
+       }
+
+       if (OutputsWritten & (1 << VERT_RESULT_FOGC)) {
+               c->code->outputs[VERT_RESULT_FOGC] = cur_reg++;
+       }
+}
+
+/**
+ * The NV_vertex_program spec mandates that all registers be
+ * initialized to zero. We do this here unconditionally.
+ *
+ * \note We rely on dead-code elimination in the compiler.
+ */
+static void initialize_NV_registers(struct radeon_compiler * compiler)
+{
+       unsigned int reg;
+       struct rc_instruction * inst;
+
+       for(reg = 0; reg < 12; ++reg) {
+               inst = rc_insert_new_instruction(compiler, &compiler->Program.Instructions);
+               inst->U.I.Opcode = RC_OPCODE_MOV;
+               inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
+               inst->U.I.DstReg.Index = reg;
+               inst->U.I.SrcReg[0].File = RC_FILE_NONE;
+               inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000;
+       }
+
+       inst = rc_insert_new_instruction(compiler, &compiler->Program.Instructions);
+       inst->U.I.Opcode = RC_OPCODE_ARL;
+       inst->U.I.DstReg.File = RC_FILE_ADDRESS;
+       inst->U.I.DstReg.Index = 0;
+       inst->U.I.DstReg.WriteMask = WRITEMASK_X;
+       inst->U.I.SrcReg[0].File = RC_FILE_NONE;
+       inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000;
+}
+
 static struct r300_vertex_program *build_program(GLcontext *ctx,
                                                 struct r300_vertex_program_key *wanted_key,
                                                 const struct gl_vertex_program *mesa_vp)
@@ -140,27 +239,52 @@ static struct r300_vertex_program *build_program(GLcontext *ctx,
        _mesa_memcpy(&vp->key, wanted_key, sizeof(vp->key));
 
        rc_init(&compiler.Base);
-       compiler.Base.Debug = (RADEON_DEBUG & DEBUG_VERTS) ? GL_TRUE : GL_FALSE;
+       compiler.Base.Debug = (RADEON_DEBUG & RADEON_VERTS) ? GL_TRUE : GL_FALSE;
 
        compiler.code = &vp->code;
-       compiler.state.FogAttr = vp->key.FogAttr;
-       compiler.state.WPosAttr = vp->key.WPosAttr;
        compiler.RequiredOutputs = compute_required_outputs(vp->Base, vp->key.FpReads);
-       compiler.program = &vp->Base->Base;
+       compiler.SetHwInputOutput = &t_inputs_outputs;
 
        if (compiler.Base.Debug) {
                fprintf(stderr, "Initial vertex program:\n");
-               _mesa_print_program(compiler.program);
-               fflush(stdout);
+               _mesa_print_program(&vp->Base->Base);
+               fflush(stderr);
        }
 
        if (mesa_vp->IsPositionInvariant) {
-               _mesa_insert_mvp_code(ctx, (struct gl_vertex_program *)compiler.program);
+               _mesa_insert_mvp_code(ctx, vp->Base);
+       }
+
+       radeon_mesa_to_rc_program(&compiler.Base, &vp->Base->Base);
+
+       if (mesa_vp->IsNVProgram)
+               initialize_NV_registers(&compiler.Base);
+
+       rc_move_output(&compiler.Base, VERT_RESULT_PSIZ, VERT_RESULT_PSIZ, WRITEMASK_X);
+
+       if (vp->key.WPosAttr != FRAG_ATTRIB_MAX) {
+               rc_copy_output(&compiler.Base,
+                       VERT_RESULT_HPOS,
+                       vp->key.WPosAttr - FRAG_ATTRIB_TEX0 + VERT_RESULT_TEX0);
+       }
+
+       if (vp->key.FogAttr != FRAG_ATTRIB_MAX) {
+               rc_move_output(&compiler.Base,
+                       VERT_RESULT_FOGC,
+                       vp->key.FogAttr - FRAG_ATTRIB_TEX0 + VERT_RESULT_TEX0, WRITEMASK_X);
        }
 
        r3xx_compile_vertex_program(&compiler);
+
+       if (vp->code.constants.Count > ctx->Const.VertexProgram.MaxParameters) {
+               rc_error(&compiler.Base, "Program exceeds constant buffer size limit\n");
+       }
+
        vp->error = compiler.Base.Error;
 
+       vp->Base->Base.InputsRead = vp->code.InputsRead;
+       vp->Base->Base.OutputsWritten = vp->code.OutputsWritten;
+
        rc_destroy(&compiler.Base);
 
        return vp;
@@ -174,9 +298,23 @@ struct r300_vertex_program * r300SelectAndTranslateVertexShader(GLcontext *ctx)
        struct r300_vertex_program *vp;
 
        vpc = (struct r300_vertex_program_cont *)ctx->VertexProgram._Current;
+
+       if (!r300->selected_fp) {
+               /* This can happen when GetProgramiv is called to check
+                * whether the program runs natively.
+                *
+                * To be honest, this is not a very good solution,
+                * but solving the problem of reporting good values
+                * for those queries is tough anyway considering that
+                * we recompile vertex programs based on the precise
+                * fragment program that is in use.
+                */
+               r300SelectAndTranslateFragmentShader(ctx);
+       }
+
        wanted_key.FpReads = r300->selected_fp->InputsRead;
-       wanted_key.FogAttr = r300->selected_fp->code.fog_attr;
-       wanted_key.WPosAttr = r300->selected_fp->code.wpos_attr;
+       wanted_key.FogAttr = r300->selected_fp->fog_attr;
+       wanted_key.WPosAttr = r300->selected_fp->wpos_attr;
 
        for (vp = vpc->progs; vp; vp = vp->next) {
                if (_mesa_memcmp(&vp->key, &wanted_key, sizeof(wanted_key))
@@ -195,7 +333,6 @@ struct r300_vertex_program * r300SelectAndTranslateVertexShader(GLcontext *ctx)
 #define bump_vpu_count(ptr, new_count)   do { \
                drm_r300_cmd_header_t* _p=((drm_r300_cmd_header_t*)(ptr)); \
                int _nc=(new_count)/4; \
-               assert(_nc < 256); \
                if(_nc>_p->vpu.count)_p->vpu.count=_nc; \
        } while(0)
 
@@ -205,6 +342,8 @@ static void r300EmitVertexProgram(r300ContextPtr r300, int dest, struct r300_ver
 
        assert((code->length > 0) && (code->length % 4 == 0));
 
+       R300_STATECHANGE( r300, vap_flush );
+
        switch ((dest >> 8) & 0xf) {
                case 0:
                        R300_STATECHANGE(r300, vpi);
@@ -226,7 +365,7 @@ static void r300EmitVertexProgram(r300ContextPtr r300, int dest, struct r300_ver
                        break;
                default:
                        fprintf(stderr, "%s:%s don't know how to handle dest %04x\n", __FILE__, __FUNCTION__, dest);
-                       _mesa_exit(-1);
+                       exit(-1);
        }
 }
 
@@ -242,6 +381,7 @@ void r300SetupVertexProgram(r300ContextPtr rmesa)
        ((drm_r300_cmd_header_t *) rmesa->hw.vpi.cmd)->vpu.count = 0;
        ((drm_r300_cmd_header_t *) rmesa->hw.vps.cmd)->vpu.count = 0;
 
+       R300_STATECHANGE(rmesa, vap_flush);
        R300_STATECHANGE(rmesa, vpp);
        param_count = r300VertexProgUpdateParams(ctx, prog, (float *)&rmesa->hw.vpp.cmd[R300_VPP_PARAM_0]);
        bump_vpu_count(rmesa->hw.vpp.cmd, param_count);