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>tags/mesa-10.1-devel
@@ -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); | |||
} | |||
@@ -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); |
@@ -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; |
@@ -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 */ |
@@ -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); | |||
} | |||
@@ -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); | |||
/** |
@@ -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) |
@@ -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; |
@@ -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) |
@@ -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; |
@@ -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; |
@@ -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 ); | |||
@@ -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; |
@@ -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; | |||
} |