i915: Only mark a register as available if all components are written
authorIan Romanick <ian.d.romanick@intel.com>
Tue, 1 Feb 2011 21:35:36 +0000 (13:35 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Tue, 1 Feb 2011 21:43:36 +0000 (13:43 -0800)
Previously a register would be marked as available if any component
was written.  This caused shaders such as this:

  0: TEX TEMP[0].xyz, INPUT[14].xyyy, texture[0], 2D;
  1: MUL TEMP[1], UNIFORM[0], TEMP[0].xxxx;
  2: MAD TEMP[2], UNIFORM[1], TEMP[0].yyyy, TEMP[1];
  3: MAD TEMP[1], UNIFORM[2], TEMP[0].zzzz, TEMP[2];
  4: ADD TEMP[0].xyz, TEMP[1].xyzx, UNIFORM[3].xyzx;
  5: TEX TEMP[1].w, INPUT[14].xyyy, texture[0], 2D;
  6: MOV TEMP[0].w, TEMP[1].wwww;
  7: MOV OUTPUT[2], TEMP[0];
  8: END

to produce incorrect code such as this:

  BEGIN
  DCL S[0]
  DCL T_TEX0
  R[0] = MOV T_TEX0.xyyy
  U[0] = TEXLD S[0],R[0]
  R[0].xyz = MOV U[0]
  R[1] = MUL CONST[0], R[0].xxxx
  R[2] = MAD CONST[1], R[0].yyyy, R[1]
  R[1] = MAD CONST[2], R[0].zzzz, R[2]
  R[0].xyz = ADD R[1].xyzx, CONST[3].xyzx
  R[0] = MOV T_TEX0.xyyy
  U[0] = TEXLD S[0],R[0]
  R[1].w = MOV U[0]
  R[0].w = MOV R[1].wwww
  oC = MOV R[0]
  END

Note that T_TEX0 is copied to R[0], but the xyz components of R[0] are
still expected to hold a calculated value.

Fixes piglit tests draw-elements-vs-inputs, fp-kill, and
glsl-fs-color-matrix.  It also fixes Meego bugzilla #13005.

NOTE: This is a candidate for the 7.9 and 7.10 branches.

src/mesa/drivers/dri/i915/i915_fragprog.c

index 1c6e9845172083c5f274f288ff7c69d0a7026f4d..624f18d6710ed26c2e3de1f20a379d42a4c288a2 100644 (file)
@@ -306,6 +306,7 @@ static void calc_live_regs( struct i915_fragment_program *p )
 {
     const struct gl_fragment_program *program = p->ctx->FragmentProgram._Current;
     GLuint regsUsed = 0xffff0000;
+    uint8_t live_components[16] = { 0, };
     GLint i;
    
     for (i = program->Base.NumInstructions - 1; i >= 0; i--) {
@@ -314,13 +315,26 @@ static void calc_live_regs( struct i915_fragment_program *p )
         int a;
 
         /* Register is written to: unmark as live for this and preceeding ops */ 
-        if (inst->DstReg.File == PROGRAM_TEMPORARY)
-            regsUsed &= ~(1 << inst->DstReg.Index);
+        if (inst->DstReg.File == PROGRAM_TEMPORARY) {
+            live_components[inst->DstReg.Index] &= ~inst->DstReg.WriteMask;
+            if (live_components[inst->DstReg.Index] == 0)
+                regsUsed &= ~(1 << inst->DstReg.Index);
+        }
 
         for (a = 0; a < opArgs; a++) {
             /* Register is read from: mark as live for this and preceeding ops */ 
-            if (inst->SrcReg[a].File == PROGRAM_TEMPORARY)
+            if (inst->SrcReg[a].File == PROGRAM_TEMPORARY) {
+                unsigned c;
+
                 regsUsed |= 1 << inst->SrcReg[a].Index;
+
+                for (c = 0; c < 4; c++) {
+                    const unsigned field = GET_SWZ(inst->SrcReg[a].Swizzle, c);
+
+                    if (field <= SWIZZLE_W)
+                        live_components[inst->SrcReg[a].Index] |= (1U << field);
+                }
+            }
         }
 
         p->usedRegs[i] = regsUsed;