gallivm/llvmpipe: basic stencil testing works
authorBrian Paul <brianp@vmware.com>
Wed, 17 Mar 2010 22:24:12 +0000 (16:24 -0600)
committerBrian Paul <brianp@vmware.com>
Wed, 17 Mar 2010 22:29:34 +0000 (16:29 -0600)
Most stencil demos look OK (modulo some unrelated rendering glitches).
Only single-sided stencil test works at this point.
There are probably some bugs to be found...

src/gallium/auxiliary/gallivm/lp_bld_depth.c
src/gallium/drivers/llvmpipe/lp_jit.h

index 0cbe42c9e5a1aa9d3cf0edc587d792eff5add4d9..e4500e5aef1f84aa48e8bbe933919459aff935a2 100644 (file)
@@ -80,8 +80,8 @@
 static LLVMValueRef
 lp_build_stencil_test(struct lp_build_context *bld,
                       const struct pipe_stencil_state *stencil,
-                      LLVMValueRef stencilVals,
-                      LLVMValueRef stencilRef)
+                      LLVMValueRef stencilRef,
+                      LLVMValueRef stencilVals)
 {
    const unsigned stencilMax = 255; /* XXX fix */
    struct lp_type type = bld->type;
@@ -97,8 +97,7 @@ lp_build_stencil_test(struct lp_build_context *bld,
       stencilVals = LLVMBuildAnd(bld->builder, stencilVals, valuemask, "");
    }
 
-   res = lp_build_compare(bld->builder, bld->type, stencil->func,
-                          stencilVals, stencilRef);
+   res = lp_build_cmp(bld, stencil->func, stencilVals, stencilRef);
 
    return res;
 }
@@ -111,10 +110,11 @@ lp_build_stencil_test(struct lp_build_context *bld,
  */
 static LLVMValueRef
 lp_build_stencil_op(struct lp_build_context *bld,
+                    const struct pipe_stencil_state *stencil,
                     unsigned stencil_op,
                     LLVMValueRef stencilRef,
-                    const struct pipe_stencil_state *stencil,
-                    LLVMValueRef stencilVals)
+                    LLVMValueRef stencilVals,
+                    LLVMValueRef mask)
 
 {
    const unsigned stencilMax = 255; /* XXX fix */
@@ -125,24 +125,33 @@ lp_build_stencil_op(struct lp_build_context *bld,
    switch (stencil_op) {
    case PIPE_STENCIL_OP_KEEP:
       res = stencilVals;
+      /* we can return early for this case */
+      return res;
    case PIPE_STENCIL_OP_ZERO:
       res = bld->zero;
+      break;
    case PIPE_STENCIL_OP_REPLACE:
-      res = lp_build_broadcast_scalar(bld, stencilRef);
+      res = stencilRef;
+      break;
    case PIPE_STENCIL_OP_INCR:
       res = lp_build_add(bld, stencilVals, bld->one);
       res = lp_build_min(bld, res, max);
+      break;
    case PIPE_STENCIL_OP_DECR:
       res = lp_build_sub(bld, stencilVals, bld->one);
       res = lp_build_max(bld, res, bld->zero);
+      break;
    case PIPE_STENCIL_OP_INCR_WRAP:
       res = lp_build_add(bld, stencilVals, bld->one);
       res = LLVMBuildAnd(bld->builder, res, max, "");
+      break;
    case PIPE_STENCIL_OP_DECR_WRAP:
       res = lp_build_sub(bld, stencilVals, bld->one);
       res = LLVMBuildAnd(bld->builder, res, max, "");
+      break;
    case PIPE_STENCIL_OP_INVERT:
       res = LLVMBuildNot(bld->builder, stencilVals, "");
+      break;
    default:
       assert(0 && "bad stencil op mode");
       res = NULL;
@@ -157,6 +166,9 @@ lp_build_stencil_op(struct lp_build_context *bld,
       res = LLVMBuildOr(bld->builder, t1, t2, "t1_or_t2");
    }
 
+   /* only the update the vector elements enabled by 'mask' */
+   res = lp_build_select(bld, mask, res, stencilVals);
+
    return res;
 }
 
@@ -201,6 +213,27 @@ lp_depth_type(const struct util_format_description *format_desc,
 }
 
 
+static LLVMValueRef
+lp_build_get_stencil_ref(struct lp_build_context *bld,
+                         struct lp_type type, LLVMValueRef stencil_refs_ptr)
+{
+   LLVMValueRef indexes[2], ptr, ref, ref_vec;
+
+   /* load 0th element of the array */
+   indexes[0] = indexes[1] = LLVMConstInt(LLVMInt32Type(), 0, 0);
+   ptr = LLVMBuildGEP(bld->builder, stencil_refs_ptr, indexes, 2, "");
+   ref = LLVMBuildLoad(bld->builder, ptr, "");
+
+   /* convert int8 value to i32 */
+   ref = LLVMBuildZExt(bld->builder, ref, LLVMIntType(type.width), "");
+
+   /* make scalar into vector */
+   ref_vec = lp_build_broadcast_scalar(bld, ref);
+
+   return ref_vec;
+}
+
+
 /**
  * Generate code for performing depth and/or stencil tests.
  * We operate on a vector of values (typically a 2x2 quad).
@@ -224,12 +257,11 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
 {
    struct lp_build_context bld;
    unsigned z_swizzle, s_swizzle;
-   LLVMValueRef zs_dst;
-   LLVMValueRef z_bitmask = NULL;
-   LLVMValueRef z_pass;
-
-   (void) lp_build_stencil_test;
-   (void) lp_build_stencil_op;
+   LLVMValueRef zs_dst, z_dst = NULL;
+   LLVMValueRef stencil_vals = NULL;
+   LLVMValueRef z_bitmask = NULL, s_bitmask = NULL;
+   LLVMValueRef z_pass = NULL, s_pass_mask = NULL;
+   LLVMValueRef orig_mask = mask->value;
 
    assert(depth->enabled || stencil[0].enabled);
 
@@ -262,15 +294,16 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
    /* Setup build context */
    lp_build_context_init(&bld, builder, type);
 
+   /* Load current z/stencil value from z/stencil buffer */
    zs_dst = LLVMBuildLoad(builder, zs_dst_ptr, "");
 
-   lp_build_name(zs_dst, "zsbuf");
+   lp_build_name(zs_dst, "zsbufval");
 
    /* Align the source depth bits with the destination's, and mask out any
     * stencil or padding bits from both */
    if(format_desc->channel[z_swizzle].size == format_desc->block.bits) {
       assert(z_swizzle == 0);
-      /* nothing to do */
+      z_dst = zs_dst;
    }
    else {
       /* shift/mask bits to right-justify the Z bits */
@@ -295,28 +328,109 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
          z_bitmask = lp_build_const_int_vec(type, mask_left ^ mask_right);
       }
 
+      s_bitmask = LLVMBuildNot(builder, z_bitmask, "");
+
+      stencil_vals = LLVMBuildAnd(builder, zs_dst, s_bitmask, "");
+
       if(padding_left)
          z_src = LLVMBuildLShr(builder, z_src,
                                 lp_build_const_int_vec(type, padding_left), "");
       if(padding_right)
          z_src = LLVMBuildAnd(builder, z_src, z_bitmask, "");
       if(padding_left || padding_right)
-         zs_dst = LLVMBuildAnd(builder, zs_dst, z_bitmask, "");
+         z_dst = LLVMBuildAnd(builder, zs_dst, z_bitmask, "");
+      else
+         z_dst = zs_dst;
    }
 
-   lp_build_name(zs_dst, "zsbuf.z");
+   lp_build_name(z_dst, "zsbuf.z");
+
+   /*
+   printf("build depth %d stencil %d\n",
+          depth->enabled,
+          stencil[0].enabled);
+   */
+
+   if (stencil[0].enabled) {
+      /* Incoming stencil_refs is ptr to int8[2].  Get/convert to int32[4]. */
+      stencil_refs = lp_build_get_stencil_ref(&bld, type, stencil_refs);
 
-   /* compare src Z to dst Z, returning 'pass' mask */
-   z_pass = lp_build_cmp(&bld, depth->func, z_src, zs_dst);
-   lp_build_mask_update(mask, z_pass);
+      s_pass_mask = lp_build_stencil_test(&bld, stencil,
+                                          stencil_refs, stencil_vals);
 
-   if (depth->writemask) {
-      if(z_bitmask)
-         z_bitmask = LLVMBuildAnd(builder, mask->value, z_bitmask, "");
+      /* apply stencil-fail operator */
+      {
+         LLVMValueRef s_fail_mask = lp_build_andc(&bld, orig_mask, s_pass_mask);
+         stencil_vals = lp_build_stencil_op(&bld, stencil, stencil[0].fail_op,
+                                            stencil_refs, stencil_vals,
+                                            s_fail_mask);
+      }
+   }
+
+   if (depth->enabled) {
+      /* compare src Z to dst Z, returning 'pass' mask */
+      z_pass = lp_build_cmp(&bld, depth->func, z_src, z_dst);
+
+      if (!stencil[0].enabled) {
+         /* We can potentially skip all remaining operations here, but only
+          * if stencil is disabled because we still need to update the stencil
+          * buffer values.  Don't need to update Z buffer values.
+          */
+         lp_build_mask_update(mask, z_pass);
+      }
+
+      if (depth->writemask) {
+         if(z_bitmask)
+            z_bitmask = LLVMBuildAnd(builder, mask->value, z_bitmask, "");
+         else
+            z_bitmask = mask->value;
+
+         z_dst = lp_build_select(&bld, z_bitmask, z_src, z_dst);
+      }
+
+      if (stencil[0].enabled) {
+         /* update stencil buffer values according to z pass/fail result */
+         LLVMValueRef z_fail_mask, z_pass_mask;
+
+         /* apply Z-fail operator */
+         z_fail_mask = lp_build_andc(&bld, orig_mask, z_pass);
+         stencil_vals = lp_build_stencil_op(&bld, stencil, stencil[0].zfail_op,
+                                            stencil_refs, stencil_vals,
+                                            z_fail_mask);
+
+         /* apply Z-pass operator */
+         z_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, z_pass, "");
+         stencil_vals = lp_build_stencil_op(&bld, stencil, stencil[0].zpass_op,
+                                            stencil_refs, stencil_vals,
+                                            z_pass_mask);
+      }
+   }
+   else {
+      /* No depth test: apply Z-pass operator to stencil buffer values which
+       * passed the stencil test.
+       */
+      s_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, s_pass_mask, "");
+      stencil_vals = lp_build_stencil_op(&bld, stencil, stencil[0].zpass_op,
+                                         stencil_refs, stencil_vals, s_pass_mask);
+   }
+
+   /* Finally, merge/store the z/stencil values */
+   if ((depth->enabled && depth->writemask) ||
+       (stencil[0].enabled && stencil[0].writemask)) {
+
+      if (z_dst && stencil_vals)
+         zs_dst = LLVMBuildOr(bld.builder, z_dst, stencil_vals, "");
+      else if (z_dst)
+         zs_dst = z_dst;
       else
-         z_bitmask = mask->value;
+         zs_dst = stencil_vals;
 
-      zs_dst = lp_build_select(&bld, z_bitmask, z_src, zs_dst);
       LLVMBuildStore(builder, zs_dst, zs_dst_ptr);
    }
+
+   if (s_pass_mask)
+      lp_build_mask_update(mask, s_pass_mask);
+
+   if (depth->enabled && stencil[0].enabled)
+      lp_build_mask_update(mask, z_pass);
 }
index 843345c62d067cf89b183898ebc6a5cbcaa1391e..63e05c5d5e18af193843d186e19f409d49587973 100644 (file)
@@ -121,7 +121,7 @@ enum {
    lp_build_struct_get(_builder, _ptr, LP_JIT_CTX_ALPHA_REF, "alpha_ref_value")
 
 #define lp_jit_context_stencil_ref_values(_builder, _ptr) \
-   lp_build_struct_get(_builder, _ptr, LP_JIT_CTX_STENCIL_REF, "stencil_ref")
+   lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CTX_STENCIL_REF, "stencil_ref")
 
 #define lp_jit_context_scissor_xmin_value(_builder, _ptr) \
    lp_build_struct_get(_builder, _ptr, LP_JIT_CTX_SCISSOR_XMIN, "scissor_xmin")