From: Matthew McClure Date: Tue, 29 Oct 2013 20:36:41 +0000 (-0700) Subject: draw,llvmpipe,util: add depth bias calculation for arb_depth_buffer_float X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f9e2c24326869542c9b43220f63dd9841c6de38f;p=mesa.git draw,llvmpipe,util: add depth bias calculation for arb_depth_buffer_float With this patch, the llvmpipe and draw modules will calculate the depth bias according to floating point depth buffer semantics described in the arb_depth_buffer_float specification, when the driver has a z buffer bound with a format type of UTIL_FORMAT_TYPE_FLOAT. By default, the driver will use the existing UNORM calculation for depth bias. A new function, draw_set_zs_format, was added to calculate the Minimum Resolvable Depth value and floating point depth sense for the draw module. Reviewed-by: Jose Fonseca Reviewed-by: Roland Scheidegger --- diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 641dd82ee28..2b3bc0d0ece 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -38,6 +38,7 @@ #include "util/u_inlines.h" #include "util/u_helpers.h" #include "util/u_prim.h" +#include "util/u_format.h" #include "draw_context.h" #include "draw_pipe.h" #include "draw_prim_assembler.h" @@ -164,6 +165,8 @@ boolean draw_init(struct draw_context *draw) draw->quads_always_flatshade_last = !draw->pipe->screen->get_param( draw->pipe->screen, PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION); + draw->floating_point_depth = false; + return TRUE; } @@ -233,15 +236,20 @@ void draw_flush( struct draw_context *draw ) /** - * Specify the Minimum Resolvable Depth factor for polygon offset. + * Specify the depth stencil format for the draw pipeline. This function + * determines the Minimum Resolvable Depth factor for polygon offset. * This factor potentially depends on the number of Z buffer bits, * the rasterization algorithm and the arithmetic performed on Z - * values between vertex shading and rasterization. It will vary - * from one driver to another. + * values between vertex shading and rasterization. */ -void draw_set_mrd(struct draw_context *draw, double mrd) +void draw_set_zs_format(struct draw_context *draw, enum pipe_format format) { - draw->mrd = mrd; + const struct util_format_description *desc = util_format_description(format); + + draw->floating_point_depth = + (util_get_depth_format_type(desc) == UTIL_FORMAT_TYPE_FLOAT); + + draw->mrd = util_get_depth_format_mrd(desc); } diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h index 46d0de6f853..e2e0cb4dad6 100644 --- a/src/gallium/auxiliary/draw/draw_context.h +++ b/src/gallium/auxiliary/draw/draw_context.h @@ -111,7 +111,7 @@ void draw_enable_line_stipple(struct draw_context *draw, boolean enable); void draw_enable_point_sprites(struct draw_context *draw, boolean enable); -void draw_set_mrd(struct draw_context *draw, double mrd); +void draw_set_zs_format(struct draw_context *draw, enum pipe_format format); boolean draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe); diff --git a/src/gallium/auxiliary/draw/draw_pipe_offset.c b/src/gallium/auxiliary/draw/draw_pipe_offset.c index 3578525051f..8071bc77b80 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_offset.c +++ b/src/gallium/auxiliary/draw/draw_pipe_offset.c @@ -32,6 +32,7 @@ * \author Brian Paul */ +#include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" #include "draw_pipe.h" @@ -89,7 +90,22 @@ static void do_offset_tri( struct draw_stage *stage, float dzdx = fabsf(a * inv_det); float dzdy = fabsf(b * inv_det); - float zoffset = offset->units + MAX2(dzdx, dzdy) * offset->scale; + float zoffset, maxz, bias, mult; + + mult = MAX2(dzdx, dzdy) * offset->scale; + + if (stage->draw->floating_point_depth) { + maxz = MAX3(v0[2], v1[2], v2[2]); + + /** + * XXX: TODO optimize this to quickly resolve a pow2 number through + * an exponent only operation. + */ + bias = offset->units * util_fast_exp2(util_get_float32_exponent(maxz) - 23); + zoffset = bias + mult; + } else { + zoffset = offset->units + mult; + } if (offset->clamp) zoffset = (offset->clamp < 0.0f) ? MAX2(zoffset, offset->clamp) : @@ -157,7 +173,17 @@ static void offset_first_tri( struct draw_stage *stage, if (do_offset) { offset->scale = rast->offset_scale; offset->clamp = rast->offset_clamp; - offset->units = (float) (rast->offset_units * stage->draw->mrd); + + /* + * If depth is floating point, depth bias is calculated with respect + * to the primitive's maximum Z value. Retain the original depth bias + * value until that stage. + */ + if (stage->draw->floating_point_depth) { + offset->units = (float) rast->offset_units; + } else { + offset->units = (float) (rast->offset_units * stage->draw->mrd); + } } else { offset->scale = 0.0f; diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index ba93b093377..fbe25a264c5 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -236,6 +236,8 @@ struct draw_context boolean dump_vs; + /** Depth format and bias related settings. */ + boolean floating_point_depth; double mrd; /**< minimum resolvable depth value, for polygon offset */ /** Current rasterizer state given to us by the driver */ diff --git a/src/gallium/auxiliary/util/u_format.c b/src/gallium/auxiliary/util/u_format.c index 9ef3bb53ff2..6b602bf3262 100644 --- a/src/gallium/auxiliary/util/u_format.c +++ b/src/gallium/auxiliary/util/u_format.c @@ -215,9 +215,8 @@ util_format_is_supported(enum pipe_format format, unsigned bind) * default MRD will be 1.0 / ((1 << 24) - 1). */ double -util_get_depth_format_mrd(enum pipe_format format) +util_get_depth_format_mrd(const struct util_format_description *desc) { - struct util_format_description *format_desc; /* * Depth buffer formats without a depth component OR scenarios * without a bound depth buffer default to D24. @@ -225,23 +224,20 @@ util_get_depth_format_mrd(enum pipe_format format) double mrd = 1.0 / ((1 << 24) - 1); unsigned depth_channel; - format_desc = (struct util_format_description *) - util_format_description(format); - - assert(format_desc); + assert(desc); /* * Some depth formats do not store the depth component in the first * channel, detect the format and adjust the depth channel. Get the * swizzled depth component channel. */ - depth_channel = format_desc->swizzle[0]; + depth_channel = desc->swizzle[0]; - if (format_desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED && - format_desc->channel[depth_channel].normalized) { + if (desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED && + desc->channel[depth_channel].normalized) { int depth_bits; - depth_bits = format_desc->channel[depth_channel].size; + depth_bits = desc->channel[depth_channel].size; mrd = 1.0 / ((1ULL << depth_bits) - 1); } diff --git a/src/gallium/auxiliary/util/u_format.h b/src/gallium/auxiliary/util/u_format.h index 369c3994ad3..0fbaf4cc154 100644 --- a/src/gallium/auxiliary/util/u_format.h +++ b/src/gallium/auxiliary/util/u_format.h @@ -545,6 +545,22 @@ util_format_is_depth_and_stencil(enum pipe_format format) } +/** + * Calculates the depth format type based upon the incoming format description. + */ +static INLINE unsigned +util_get_depth_format_type(const struct util_format_description *desc) +{ + unsigned depth_channel = desc->swizzle[0]; + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS && + depth_channel != UTIL_FORMAT_SWIZZLE_NONE) { + return desc->channel[depth_channel].type; + } else { + return UTIL_FORMAT_TYPE_VOID; + } +} + + /** * Calculates the MRD for the depth format. MRD is used in depth bias * for UNORM and unbound depth buffers. When the depth buffer is floating @@ -552,7 +568,7 @@ util_format_is_depth_and_stencil(enum pipe_format format) * default MRD will be 1.0 / ((1 << 24) - 1). */ double -util_get_depth_format_mrd(enum pipe_format format); +util_get_depth_format_mrd(const struct util_format_description *desc); /** diff --git a/src/gallium/auxiliary/util/u_math.h b/src/gallium/auxiliary/util/u_math.h index f5c14ef8d56..426d5daa78c 100644 --- a/src/gallium/auxiliary/util/u_math.h +++ b/src/gallium/auxiliary/util/u_math.h @@ -245,6 +245,19 @@ union di { }; +/** + * Extract the IEEE float32 exponent. + */ +static INLINE signed +util_get_float32_exponent(float x) { + union fi f; + + f.f = x; + + return ((f.ui >> 23) & 0xff) - 127; +} + + /** * Fast version of 2^x * Identity: exp2(a + b) = exp2(a) * exp2(b) diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h index 106288a6ad3..9ec18e8429e 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.h +++ b/src/gallium/drivers/llvmpipe/lp_context.h @@ -124,9 +124,10 @@ struct llvmpipe_context { /** A fake frontface output for unfilled primitives */ int face_slot; - /**< minimum resolvable depth value, for polygon offset */ - double mrd; - + /** Depth format and bias settings. */ + boolean floating_point_depth; + double mrd; /**< minimum resolvable depth value, for polygon offset */ + /** The tiling engine */ struct lp_setup_context *setup; struct lp_setup_variant setup_variant; diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c index 8aee92b1b96..47e413b776c 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_derived.c +++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c @@ -186,7 +186,8 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe ) llvmpipe_update_fs( llvmpipe ); if (llvmpipe->dirty & (LP_NEW_FS | - LP_NEW_RASTERIZER)) + LP_NEW_FRAMEBUFFER | + LP_NEW_RASTERIZER)) llvmpipe_update_setup( llvmpipe ); if (llvmpipe->dirty & LP_NEW_BLEND_COLOR) diff --git a/src/gallium/drivers/llvmpipe/lp_state_setup.c b/src/gallium/drivers/llvmpipe/lp_state_setup.c index dab5096c61d..ccc9fb902f3 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_state_setup.c @@ -256,6 +256,7 @@ lp_do_offset_tri(struct gallivm_state *gallivm, LLVMBuilderRef b = gallivm->builder; struct lp_build_context bld; struct lp_build_context flt_scalar_bld; + struct lp_build_context int_scalar_bld; LLVMValueRef zoffset, mult; LLVMValueRef z0_new, z1_new, z2_new; LLVMValueRef dzdxdzdy, dzdx, dzdy, dzxyz20, dyzzx01, dyzzx01_dzxyz20, dzx01_dyz20; @@ -267,6 +268,8 @@ lp_do_offset_tri(struct gallivm_state *gallivm, LLVMValueRef zeroi = lp_build_const_int32(gallivm, 0); LLVMValueRef twoi = lp_build_const_int32(gallivm, 2); LLVMValueRef threei = lp_build_const_int32(gallivm, 3); + LLVMValueRef mantissa_bits, exp, bias; + LLVMValueRef maxz_value, maxz0z1_value; /* (res12) = cross(e,f).xy */ shuffles[0] = twoi; @@ -300,17 +303,56 @@ lp_do_offset_tri(struct gallivm_state *gallivm, dzdx = LLVMBuildExtractElement(b, dzdxdzdy, zeroi, ""); dzdy = LLVMBuildExtractElement(b, dzdxdzdy, onei, ""); - /* zoffset = pgon_offset_units + MAX2(dzdx, dzdy) * pgon_offset_scale */ + /* mult = MAX2(dzdx, dzdy) * pgon_offset_scale */ max = LLVMBuildFCmp(b, LLVMRealUGT, dzdx, dzdy, ""); max_value = LLVMBuildSelect(b, max, dzdx, dzdy, "max"); mult = LLVMBuildFMul(b, max_value, lp_build_const_float(gallivm, key->pgon_offset_scale), ""); - zoffset = LLVMBuildFAdd(b, - lp_build_const_float(gallivm, key->pgon_offset_units), - mult, "zoffset"); lp_build_context_init(&flt_scalar_bld, gallivm, lp_type_float_vec(32, 32)); + + if (key->floating_point_depth) { + /* + * bias = pgon_offset_units * 2^(exponent(max(z0, z1, z2)) - mantissa_bits) + + * MAX2(dzdx, dzdy) * pgon_offset_scale + * + * NOTE: Assumes IEEE float32. + */ + lp_build_context_init(&int_scalar_bld, gallivm, lp_type_int_vec(32, 32)); + + mantissa_bits = lp_build_const_int32(gallivm, 23); + + maxz0z1_value = lp_build_max(&flt_scalar_bld, + LLVMBuildExtractElement(b, attribv[0], twoi, ""), + LLVMBuildExtractElement(b, attribv[1], twoi, "")); + + maxz_value = lp_build_max(&flt_scalar_bld, + LLVMBuildExtractElement(b, attribv[2], twoi, ""), + maxz0z1_value); + + /** + * XXX: TODO optimize this to quickly resolve a pow2 number through + * an exponent only operation. + */ + exp = lp_build_extract_exponent(&flt_scalar_bld, maxz_value, 0); + exp = lp_build_sub(&int_scalar_bld, exp, mantissa_bits); + exp = lp_build_int_to_float(&flt_scalar_bld, exp); + + bias = LLVMBuildFMul(b, lp_build_exp2(&flt_scalar_bld, exp), + lp_build_const_float(gallivm, key->pgon_offset_units), + "bias"); + + zoffset = LLVMBuildFAdd(b, bias, mult, "zoffset"); + } else { + /* + * bias = pgon_offset_units + MAX2(dzdx, dzdy) * pgon_offset_scale + */ + zoffset = LLVMBuildFAdd(b, + lp_build_const_float(gallivm, key->pgon_offset_units), + mult, "zoffset"); + } + if (key->pgon_offset_clamp > 0) { zoffset = lp_build_min(&flt_scalar_bld, lp_build_const_float(gallivm, key->pgon_offset_clamp), @@ -849,7 +891,20 @@ lp_make_setup_variant_key(struct llvmpipe_context *lp, assert(key->spec_slot == lp->color_slot [1]); assert(key->bspec_slot == lp->bcolor_slot[1]); - key->pgon_offset_units = (float) (lp->rasterizer->offset_units * lp->mrd); + /* + * If depth is floating point, depth bias is calculated with respect + * to the primitive's maximum Z value. Retain the original depth bias + * value until that stage. + */ + key->floating_point_depth = lp->floating_point_depth; + + if (key->floating_point_depth) { + key->pgon_offset_units = (float) lp->rasterizer->offset_units; + } else { + key->pgon_offset_units = + (float) (lp->rasterizer->offset_units * lp->mrd); + } + key->pgon_offset_scale = lp->rasterizer->offset_scale; key->pgon_offset_clamp = lp->rasterizer->offset_clamp; key->pad = 0; diff --git a/src/gallium/drivers/llvmpipe/lp_state_setup.h b/src/gallium/drivers/llvmpipe/lp_state_setup.h index f49e575aa1f..82af8350fb7 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_setup.h +++ b/src/gallium/drivers/llvmpipe/lp_state_setup.h @@ -25,7 +25,8 @@ struct lp_setup_variant_key { unsigned flatshade_first:1; unsigned pixel_center_half:1; unsigned twoside:1; - unsigned pad:5; + unsigned floating_point_depth:1; + unsigned pad:4; /* TODO: get those floats out of the key and use a jit_context for setup */ float pgon_offset_units; diff --git a/src/gallium/drivers/llvmpipe/lp_state_surface.c b/src/gallium/drivers/llvmpipe/lp_state_surface.c index 89098410280..c228c63d139 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_surface.c +++ b/src/gallium/drivers/llvmpipe/lp_state_surface.c @@ -57,24 +57,32 @@ llvmpipe_set_framebuffer_state(struct pipe_context *pipe, assert(fb->height <= LP_MAX_HEIGHT); if (changed) { + /* + * If no depth buffer is bound, send the utility function the default + * format for no bound depth (PIPE_FORMAT_NONE). + */ + enum pipe_format depth_format = fb->zsbuf ? + fb->zsbuf->format : PIPE_FORMAT_NONE; + const struct util_format_description *depth_desc = + util_format_description(depth_format); + util_copy_framebuffer_state(&lp->framebuffer, fb); if (LP_PERF & PERF_NO_DEPTH) { pipe_surface_reference(&lp->framebuffer.zsbuf, NULL); } - /* Tell draw module how deep the Z/depth buffer is. - * - * If no depth buffer is bound, send the utility function the default - * format for no bound depth (PIPE_FORMAT_NONE). - * - * FIXME: mrd constant isn't right should use a value derived from - * current primitive not a constant (for float depth buffers) + /* + * Calculate the floating point depth sense and Minimum Resolvable Depth + * value for the llvmpipe module. This is separate from the draw module. */ - lp->mrd = util_get_depth_format_mrd((lp->framebuffer.zsbuf) ? - lp->framebuffer.zsbuf->format : PIPE_FORMAT_NONE); + lp->floating_point_depth = + (util_get_depth_format_type(depth_desc) == UTIL_FORMAT_TYPE_FLOAT); + + lp->mrd = util_get_depth_format_mrd(depth_desc); - draw_set_mrd(lp->draw, lp->mrd); + /* Tell the draw module how deep the Z/depth buffer is. */ + draw_set_zs_format(lp->draw, depth_format); lp_setup_bind_framebuffer( lp->setup, &lp->framebuffer ); diff --git a/src/gallium/drivers/softpipe/sp_state_surface.c b/src/gallium/drivers/softpipe/sp_state_surface.c index c0bd1f757e1..922f5687a96 100644 --- a/src/gallium/drivers/softpipe/sp_state_surface.c +++ b/src/gallium/drivers/softpipe/sp_state_surface.c @@ -82,21 +82,14 @@ softpipe_set_framebuffer_state(struct pipe_context *pipe, /* update cache */ sp_tile_cache_set_surface(sp->zsbuf_cache, fb->zsbuf); - /* Tell draw module how deep the Z/depth buffer is */ - if (sp->framebuffer.zsbuf) { - int depth_bits; - double mrd; - depth_bits = util_format_get_component_bits(sp->framebuffer.zsbuf->format, - UTIL_FORMAT_COLORSPACE_ZS, - 0); - if (depth_bits > 16) { - mrd = 0.0000001; - } - else { - mrd = 0.00002; - } - draw_set_mrd(sp->draw, mrd); - } + /* Tell draw module how deep the Z/depth buffer is + * + * If no depth buffer is bound, send the utility function the + * format for no bound depth (PIPE_FORMAT_NONE). + */ + draw_set_zs_format(sp->draw, + (sp->framebuffer.zsbuf) ? + sp->framebuffer.zsbuf->format : PIPE_FORMAT_NONE); } sp->framebuffer.width = fb->width; diff --git a/src/gallium/drivers/svga/svga_swtnl_state.c b/src/gallium/drivers/svga/svga_swtnl_state.c index d66f1a1515a..e62698e11f4 100644 --- a/src/gallium/drivers/svga/svga_swtnl_state.c +++ b/src/gallium/drivers/svga/svga_swtnl_state.c @@ -121,9 +121,15 @@ update_swtnl_draw( struct svga_context *svga, &svga->curr.rast->templ, (void *) svga->curr.rast); + /* Tell the draw module how deep the Z/depth buffer is. + * + * If no depth buffer is bound, send the utility function the + * format for no bound depth (PIPE_FORMAT_NONE). + */ if (dirty & SVGA_NEW_FRAME_BUFFER) - draw_set_mrd(svga->swtnl.draw, - svga->curr.depthscale); + draw_set_zs_format(svga->swtnl.draw, + (svga->curr.framebuffer.zsbuf) ? + svga->curr.framebuffer.zsbuf->format : PIPE_FORMAT_NONE); return PIPE_OK; }