From fecd4cde501e8b0b5d057a9cc9d2e3af8d853d9e Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 17 Mar 2010 16:24:12 -0600 Subject: [PATCH] gallivm/llvmpipe: basic stencil testing works 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 | 164 +++++++++++++++++++++++---- src/gallium/drivers/llvmpipe/lp_jit.h | 2 +- 2 files changed, 140 insertions(+), 26 deletions(-) diff --git a/src/gallium/auxiliary/gallivm/lp_bld_depth.c b/src/gallium/auxiliary/gallivm/lp_bld_depth.c index 0cbe42c..e4500e5 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_depth.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_depth.c @@ -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); } diff --git a/src/gallium/drivers/llvmpipe/lp_jit.h b/src/gallium/drivers/llvmpipe/lp_jit.h index 843345c..63e05c5 100644 --- a/src/gallium/drivers/llvmpipe/lp_jit.h +++ b/src/gallium/drivers/llvmpipe/lp_jit.h @@ -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") -- 2.7.4