X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fr300%2Fr300_hyperz.c;h=0f021e9f4e8ae8d077b959b982aab85adc6cd919;hb=d64c6d2ffc086bde7a025269b80c0980f7d908f1;hp=b41b6b1508d88086354f57dbd6c28fe0c1f5af26;hpb=7662e3519bef3802024da3050b886068281e02b1;p=mesa.git diff --git a/src/gallium/drivers/r300/r300_hyperz.c b/src/gallium/drivers/r300/r300_hyperz.c index b41b6b1508d..0f021e9f4e8 100644 --- a/src/gallium/drivers/r300/r300_hyperz.c +++ b/src/gallium/drivers/r300/r300_hyperz.c @@ -21,43 +21,244 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#include "r300_hyperz.h" #include "r300_context.h" #include "r300_reg.h" #include "r300_fs.h" +#include "util/u_format.h" +#include "util/u_mm.h" + +/* + HiZ rules - taken from various docs + 1. HiZ only works on depth values + 2. Cannot HiZ if stencil fail or zfail is !KEEP + 3. on R300/400, HiZ is disabled if depth test is EQUAL + 4. comparison changes without clears usually mean disabling HiZ +*/ +/*****************************************************************************/ +/* The HyperZ setup */ +/*****************************************************************************/ + +static enum r300_hiz_func r300_get_hiz_func(struct r300_context *r300) +{ + struct r300_dsa_state *dsa = r300->dsa_state.state; + + switch (dsa->dsa.depth.func) { + case PIPE_FUNC_NEVER: + case PIPE_FUNC_EQUAL: + case PIPE_FUNC_NOTEQUAL: + case PIPE_FUNC_ALWAYS: + default: + /* Guess MAX for uncertain cases. */ + case PIPE_FUNC_LESS: + case PIPE_FUNC_LEQUAL: + return HIZ_FUNC_MAX; + + case PIPE_FUNC_GREATER: + case PIPE_FUNC_GEQUAL: + return HIZ_FUNC_MIN; + } +} + +/* Return what's used for the depth test (either minimum or maximum). */ +static unsigned r300_get_sc_hz_max(struct r300_context *r300) +{ + struct r300_dsa_state *dsa = r300->dsa_state.state; + unsigned func = dsa->dsa.depth.func; + + return func >= PIPE_FUNC_GREATER ? R300_SC_HYPERZ_MAX : R300_SC_HYPERZ_MIN; +} + +static boolean r300_is_hiz_func_valid(struct r300_context *r300) +{ + struct r300_dsa_state *dsa = r300->dsa_state.state; + unsigned func = dsa->dsa.depth.func; + + if (r300->hiz_func == HIZ_FUNC_NONE) + return TRUE; + + /* func1 is less/lessthan */ + if (r300->hiz_func == HIZ_FUNC_MAX && + (func == PIPE_FUNC_GEQUAL || func == PIPE_FUNC_GREATER)) + return FALSE; + + /* func1 is greater/greaterthan */ + if (r300->hiz_func == HIZ_FUNC_MIN && + (func == PIPE_FUNC_LESS || func == PIPE_FUNC_LEQUAL)) + return FALSE; + + return TRUE; +} + +static boolean r300_dsa_stencil_op_not_keep(struct pipe_stencil_state *s) +{ + return s->enabled && (s->fail_op != PIPE_STENCIL_OP_KEEP || + s->zfail_op != PIPE_STENCIL_OP_KEEP); +} + +static boolean r300_hiz_allowed(struct r300_context *r300) +{ + struct r300_dsa_state *dsa = r300->dsa_state.state; + struct r300_screen *r300screen = r300->screen; + + if (r300_fragment_shader_writes_depth(r300_fs(r300))) + return FALSE; + + if (r300->query_current) + return FALSE; + + /* If the depth function is inverted, HiZ must be disabled. */ + if (!r300_is_hiz_func_valid(r300)) + return FALSE; + + /* if stencil fail/zfail op is not KEEP */ + if (r300_dsa_stencil_op_not_keep(&dsa->dsa.stencil[0]) || + r300_dsa_stencil_op_not_keep(&dsa->dsa.stencil[1])) + return FALSE; + + if (dsa->dsa.depth.enabled) { + /* if depth func is EQUAL pre-r500 */ + if (dsa->dsa.depth.func == PIPE_FUNC_EQUAL && !r300screen->caps.is_r500) + return FALSE; + + /* if depth func is NOTEQUAL */ + if (dsa->dsa.depth.func == PIPE_FUNC_NOTEQUAL) + return FALSE; + } + return TRUE; +} + +static void r300_update_hyperz(struct r300_context* r300) +{ + struct r300_hyperz_state *z = + (struct r300_hyperz_state*)r300->hyperz_state.state; + struct pipe_framebuffer_state *fb = + (struct pipe_framebuffer_state*)r300->fb_state.state; + struct r300_dsa_state *dsa = r300->dsa_state.state; + struct r300_resource *zstex = + fb->zsbuf ? r300_resource(fb->zsbuf->texture) : NULL; + + z->gb_z_peq_config = 0; + z->zb_bw_cntl = 0; + z->sc_hyperz = R300_SC_HYPERZ_ADJ_2; + z->flush = 0; + + if (r300->cbzb_clear) { + z->zb_bw_cntl |= R300_ZB_CB_CLEAR_CACHE_LINE_WRITE_ONLY; + return; + } + + if (!zstex || !r300->hyperz_enabled) + return; + + /* Set the size of ZMASK tiles. */ + if (zstex->tex.zcomp8x8[fb->zsbuf->u.tex.level]) { + z->gb_z_peq_config |= R300_GB_Z_PEQ_CONFIG_Z_PEQ_SIZE_8_8; + } + + /* R500-specific features and optimizations. */ + if (r300->screen->caps.is_r500) { + z->zb_bw_cntl |= R500_PEQ_PACKING_ENABLE | + R500_COVERED_PTR_MASKING_ENABLE; + } + + /* Setup decompression if needed. No other HyperZ setting is required. */ + if (r300->zmask_decompress) { + z->zb_bw_cntl |= R300_FAST_FILL_ENABLE | + R300_RD_COMP_ENABLE; + return; + } + + /* Do not set anything if depth and stencil tests are off. */ + if (!dsa->dsa.depth.enabled && + !dsa->dsa.stencil[0].enabled && + !dsa->dsa.stencil[1].enabled) { + assert(!dsa->dsa.depth.writemask); + return; + } + + /* Zbuffer compression. */ + if (r300->zmask_in_use && !r300->locked_zbuffer) { + z->zb_bw_cntl |= R300_FAST_FILL_ENABLE | + R300_RD_COMP_ENABLE | + R300_WR_COMP_ENABLE; + } + + /* HiZ. */ + if (r300->hiz_in_use && !r300->locked_zbuffer) { + /* HiZ cannot be used under some circumstances. */ + if (!r300_hiz_allowed(r300)) { + /* If writemask is disabled, the HiZ memory will not be changed, + * so we can keep its content for later. */ + if (dsa->dsa.depth.writemask) { + r300->hiz_in_use = FALSE; + } + return; + } + DBG(r300, DBG_HYPERZ, "r300: Z-func: %i\n", dsa->dsa.depth.func); + + /* Set the HiZ function if needed. */ + if (r300->hiz_func == HIZ_FUNC_NONE) { + r300->hiz_func = r300_get_hiz_func(r300); + } + + /* Setup the HiZ bits. */ + z->zb_bw_cntl |= R300_HIZ_ENABLE | + (r300->hiz_func == HIZ_FUNC_MIN ? R300_HIZ_MIN : R300_HIZ_MAX); + + z->sc_hyperz |= R300_SC_HYPERZ_ENABLE | + r300_get_sc_hz_max(r300); + + if (r300->screen->caps.is_r500) { + z->zb_bw_cntl |= R500_HIZ_EQUAL_REJECT_ENABLE; + } + } +} + /*****************************************************************************/ /* The ZTOP state */ /*****************************************************************************/ -static boolean r300_dsa_writes_depth_stencil(struct r300_dsa_state* dsa) +static boolean r300_dsa_writes_stencil( + struct pipe_stencil_state *s) { - /* We are interested only in the cases when a new depth or stencil value - * can be written and changed. */ - - /* We might optionally check for [Z func: never] and inspect the stencil - * state in a similar fashion, but it's not terribly important. */ - return (dsa->z_buffer_control & R300_Z_WRITE_ENABLE) || - (dsa->stencil_ref_mask & R300_STENCILWRITEMASK_MASK) || - ((dsa->z_buffer_control & R500_STENCIL_REFMASK_FRONT_BACK) && - (dsa->stencil_ref_bf & R300_STENCILWRITEMASK_MASK)); + return s->enabled && s->writemask && + (s->fail_op != PIPE_STENCIL_OP_KEEP || + s->zfail_op != PIPE_STENCIL_OP_KEEP || + s->zpass_op != PIPE_STENCIL_OP_KEEP); } -static boolean r300_dsa_alpha_test_enabled(struct r300_dsa_state* dsa) +static boolean r300_dsa_writes_depth_stencil( + struct pipe_depth_stencil_alpha_state *dsa) +{ + /* We are interested only in the cases when a depth or stencil value + * can be changed. */ + + if (dsa->depth.enabled && dsa->depth.writemask && + dsa->depth.func != PIPE_FUNC_NEVER) + return TRUE; + + if (r300_dsa_writes_stencil(&dsa->stencil[0]) || + r300_dsa_writes_stencil(&dsa->stencil[1])) + return TRUE; + + return FALSE; +} + +static boolean r300_dsa_alpha_test_enabled( + struct pipe_depth_stencil_alpha_state *dsa) { /* We are interested only in the cases when alpha testing can kill * a fragment. */ - uint32_t af = dsa->alpha_function; - return (af & R300_FG_ALPHA_FUNC_ENABLE) && - (af & R300_FG_ALPHA_FUNC_ALWAYS) != R300_FG_ALPHA_FUNC_ALWAYS; + return dsa->alpha.enabled && dsa->alpha.func != PIPE_FUNC_ALWAYS; } static void r300_update_ztop(struct r300_context* r300) { struct r300_ztop_state* ztop_state = (struct r300_ztop_state*)r300->ztop_state.state; + uint32_t old_ztop = ztop_state->z_buffer_top; /* This is important enough that I felt it warranted a comment. * @@ -98,11 +299,15 @@ static void r300_update_ztop(struct r300_context* r300) } else { ztop_state->z_buffer_top = R300_ZTOP_ENABLE; } - - r300->ztop_state.dirty = TRUE; + if (ztop_state->z_buffer_top != old_ztop) + r300_mark_atom_dirty(r300, &r300->ztop_state); } void r300_update_hyperz_state(struct r300_context* r300) { r300_update_ztop(r300); + + if (r300->hyperz_state.dirty) { + r300_update_hyperz(r300); + } }