draw,llvmpipe,util: add depth bias calculation for arb_depth_buffer_float
authorMatthew McClure <mcclurem@vmware.com>
Tue, 29 Oct 2013 20:36:41 +0000 (13:36 -0700)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 7 Nov 2013 18:32:54 +0000 (18:32 +0000)
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 <jfonseca@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
14 files changed:
src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_context.h
src/gallium/auxiliary/draw/draw_pipe_offset.c
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/util/u_format.c
src/gallium/auxiliary/util/u_format.h
src/gallium/auxiliary/util/u_math.h
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_setup.c
src/gallium/drivers/llvmpipe/lp_state_setup.h
src/gallium/drivers/llvmpipe/lp_state_surface.c
src/gallium/drivers/softpipe/sp_state_surface.c
src/gallium/drivers/svga/svga_swtnl_state.c

index 641dd82ee28af51ef9c711a52a8ac70c1c42bd1d..2b3bc0d0ece5884810f2171aca828853905935bb 100644 (file)
@@ -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);
 }
 
 
index 46d0de6f8538e9c8dba054ad8b1b55b3df6c6cb2..e2e0cb4dad64014886c1c98f26c9a25b60573679 100644 (file)
@@ -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);
index 3578525051f463f74dd4e440d60b4de5628be0e8..8071bc77b80f76f1cfc2dacbbc12b2c4487e93a1 100644 (file)
@@ -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;
index ba93b09337753508e413aca2ca075a25d6a96265..fbe25a264c5a8f786eb65e604a3f2299fc5f2a90 100644 (file)
@@ -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 */
index 9ef3bb53ff25d053e9b6af6ccddf0d3b6cec4987..6b602bf3262a90a28c1dc07148b97271df437bdf 100644 (file)
@@ -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);
    }
 
index 369c3994ad377377e07862bb5d2718164b961034..0fbaf4cc1540625b38e25f6fb3baad89280189dd 100644 (file)
@@ -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);
 
 
 /**
index f5c14ef8d5619c38d1c5e4966f4fd6516a9a096d..426d5daa78c50f1d89ed920361067ed97e1c8710 100644 (file)
@@ -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)
index 106288a6ad36ef6fa59a3eb05fc69da684b3d032..9ec18e8429edf4d2ea0630c1c0737486b884d78b 100644 (file)
@@ -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;
index 8aee92b1b9607d77194466d9d85721a7c9cd2ba1..47e413b776c17ad2a5cb32059968ea2765b85f2f 100644 (file)
@@ -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)
index dab5096c61dd11fe956babb88ae20a2d380d90a9..ccc9fb902f33ef6030d2e69d944de546c4d4b62d 100644 (file)
@@ -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;
index f49e575aa1f2ae30f8976a5a6e3da8a389ad79ea..82af8350fb7090676d2827491f90a68a3146ab25 100644 (file)
@@ -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;
index 8909841028074559a29907eddbc2f07cbcd8120c..c228c63d13909091ddf13d3639ef38bf1c57467b 100644 (file)
@@ -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 );
 
index c0bd1f757e1d891f8e3adfaf7bb9a06fed857aa0..922f5687a9629698032511fc0f9a8deaf046759f 100644 (file)
@@ -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;
index d66f1a1515a441a5640b49015075f4a547f253fa..e62698e11f4d76eb51414dd1627403968ffc6516 100644 (file)
@@ -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;
 }