cell: Fix various stencil test code-gen bugs
authorIan Romanick <idr@us.ibm.com>
Tue, 18 Mar 2008 22:59:33 +0000 (15:59 -0700)
committerIan Romanick <idr@us.ibm.com>
Tue, 18 Mar 2008 23:00:49 +0000 (16:00 -0700)
src/gallium/drivers/cell/ppu/cell_state_per_fragment.c

index 11c0aa5b23cd181463b2f9d21f9d5e5c2519d682..9c47968459694300de922eb6aed54daa55dd1cf3 100644 (file)
@@ -199,52 +199,62 @@ emit_depth_test(struct pipe_depth_stencil_alpha_state *dsa,
 
 /**
  * \note Emits a maximum of 5 instructions.
+ *
+ * \warning
+ * Since \c out and \c in might be the same register, this routine cannot
+ * generate code that uses \c out as a temporary.
  */
 static void
 emit_stencil_op(struct spe_function *f,
                 int out, int in, int mask, unsigned op, unsigned ref)
 {
    const int clamp = spe_allocate_available_register(f);
-   const int tmp = spe_allocate_available_register(f);
+   const int clamp_mask = spe_allocate_available_register(f);
+   const int result = spe_allocate_available_register(f);
 
    switch(op) {
    case PIPE_STENCIL_OP_KEEP:
       assert(0);
    case PIPE_STENCIL_OP_ZERO:
-      spe_il(f, out, 0);
+      spe_il(f, result, 0);
       break;
    case PIPE_STENCIL_OP_REPLACE:
-      spe_il(f, out, ref);
+      spe_il(f, result, ref);
       break;
    case PIPE_STENCIL_OP_INCR:
       spe_il(f, clamp, 0x0ff);
-      spe_ai(f, out, in, 1);
-      spe_cgti(f, tmp, out, clamp);
-      spe_selb(f, out, out, clamp, tmp);
+      spe_ai(f, result, in, 1);
+      spe_clgti(f, clamp_mask, result, 0x0ff);
+      spe_selb(f, result, result, clamp, clamp_mask);
       break;
    case PIPE_STENCIL_OP_DECR:
       spe_il(f, clamp, 0);
-      spe_ai(f, out, in, -1);
-      spe_cgti(f, tmp, out, clamp);
-      spe_selb(f, out, clamp, out, tmp);
+      spe_ai(f, result, in, -1);
+
+      /* If "(s-1) < 0" in signed arithemtic, then "(s-1) > MAX" in unsigned
+       * arithmetic.
+       */
+      spe_clgti(f, clamp_mask, result, 0x0ff);
+      spe_selb(f, result, result, clamp, clamp_mask);
       break;
    case PIPE_STENCIL_OP_INCR_WRAP:
-      spe_ai(f, out, in, 1);
+      spe_ai(f, result, in, 1);
       break;
    case PIPE_STENCIL_OP_DECR_WRAP:
-      spe_ai(f, out, in, -1);
+      spe_ai(f, result, in, -1);
       break;
    case PIPE_STENCIL_OP_INVERT:
-      spe_nor(f, out, in, in);
+      spe_nor(f, result, in, in);
       break;
    default:
       assert(0);
    }
 
-   spe_release_register(f, tmp);
-   spe_release_register(f, clamp);
+   spe_selb(f, out, in, result, mask);
 
-   spe_selb(f, out, in, out, mask);
+   spe_release_register(f, result);
+   spe_release_register(f, clamp_mask);
+   spe_release_register(f, clamp);
 }
 
 
@@ -261,13 +271,13 @@ emit_stencil_op(struct spe_function *f,
  * \param stencil    Register containing values from stencil buffer
  * \param depth_pass Register to store mask of fragments passing stencil test
  *                   and depth test
- * 
+ *
  * \note
  * Emits a maximum of 10 + (3 * 5) = 25 instructions.
  */
 static int
 emit_stencil_test(struct pipe_depth_stencil_alpha_state *dsa,
-                  unsigned face, 
+                  unsigned face,
                   struct spe_function *f,
                   int mask,
                   int depth_mask,
@@ -284,14 +294,17 @@ emit_stencil_test(struct pipe_depth_stencil_alpha_state *dsa,
    const unsigned ref = (dsa->stencil[face].ref_value
                          & dsa->stencil[face].value_mask);
    boolean complement = FALSE;
-   int stored = spe_allocate_available_register(f);
+   int stored;
    int tmp = spe_allocate_available_register(f);
 
 
    if ((dsa->stencil[face].func != PIPE_FUNC_NEVER)
        && (dsa->stencil[face].func != PIPE_FUNC_ALWAYS)
        && (dsa->stencil[face].value_mask != 0x0ff)) {
+      stored = spe_allocate_available_register(f);
       spe_andi(f, stored, stencil, dsa->stencil[face].value_mask);
+   } else {
+      stored = stencil;
    }
 
 
@@ -332,7 +345,9 @@ emit_stencil_test(struct pipe_depth_stencil_alpha_state *dsa,
       break;
    }
 
-   spe_release_register(f, stored);
+   if (stored != stencil) {
+      spe_release_register(f, stored);
+   }
    spe_release_register(f, tmp);
 
 
@@ -362,7 +377,7 @@ emit_stencil_test(struct pipe_depth_stencil_alpha_state *dsa,
    /* Conditionally emit code to update the stencil value under various
     * condititons.  Note that there is no need to generate code under the
     * following circumstances:
-    * 
+    *
     * - Stencil write mask is zero.
     * - For stencil-fail if the stencil test is ALWAYS
     * - For depth-fail if the stencil test is NEVER
@@ -425,7 +440,7 @@ emit_stencil_test(struct pipe_depth_stencil_alpha_state *dsa,
       spe_release_register(f, face_stencil);
    } else if (dsa->stencil[face].write_mask != 0x0ff) {
       int tmp = spe_allocate_available_register(f);
-      
+
       spe_il(f, tmp, dsa->stencil[face].write_mask);
       spe_selb(f, stencil_src, stencil, stencil_src, tmp);
 
@@ -492,12 +507,12 @@ cell_generate_depth_stencil_test(struct cell_depth_stencil_alpha_state *cdsa)
          if (front_stencil != back_stencil) {
             spe_selb(f, stencil, back_stencil, front_stencil, facing);
          }
-         
-         if (back_stencil != stencil) { 
+
+         if (back_stencil != stencil) {
             spe_release_register(f, back_stencil);
          }
 
-         if (front_stencil != stencil) { 
+         if (front_stencil != stencil) {
             spe_release_register(f, front_stencil);
          }
 
@@ -505,10 +520,11 @@ cell_generate_depth_stencil_test(struct cell_depth_stencil_alpha_state *cdsa)
 
          spe_release_register(f, back_depth_pass);
       } else {
-         if (front_stencil != stencil) { 
+         if (front_stencil != stencil) {
             spe_or(f, stencil, front_stencil, front_stencil);
             spe_release_register(f, front_stencil);
          }
+         spe_or(f, mask, front_depth_pass, front_depth_pass);
       }
 
       spe_release_register(f, front_depth_pass);
@@ -997,7 +1013,7 @@ cell_generate_alpha_blend(struct cell_blend_state *cb,
                                          blend_color->color[3],
                                           frag[3], pixel[3]);
    }
-   
+
 
    if (sF[0] == sF[3]) {
       src_factor[0] = src_factor[3];
@@ -1036,7 +1052,7 @@ cell_generate_alpha_blend(struct cell_blend_state *cb,
                                     frag, pixel, dst_factor);
    }
 
-   
+
 
    func[0] = b->rgb_func;
    func[1] = func[0];