aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/llvmpipe
diff options
context:
space:
mode:
authorMatthew McClure <[email protected]>2013-10-29 13:36:41 -0700
committerJosé Fonseca <[email protected]>2013-11-07 18:32:54 +0000
commitf9e2c24326869542c9b43220f63dd9841c6de38f (patch)
treebd208be0c8a880c0665c6672138083e00eeef680 /src/gallium/drivers/llvmpipe
parent185b5a54c94ce11487146042c8eec24909187ed6 (diff)
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 <[email protected]> Reviewed-by: Roland Scheidegger <[email protected]>
Diffstat (limited to 'src/gallium/drivers/llvmpipe')
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.h7
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_derived.c3
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_setup.c65
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_setup.h3
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_surface.c28
5 files changed, 86 insertions, 20 deletions
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 );