From 1bf466270d416643e8fcacd6b790e53660303059 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 23 Mar 2018 16:18:02 -0700 Subject: [PATCH] broadcom/vc5: Fix EZ disabling and allow using GT/GE direction as well. Once we've disabled EZ for some draws, we need to not use EZ on future draws. Implementing that made implementing the GT/GE direction trivial. Fixes KHR-GLES3.shaders.fragdepth.compare.no_write on V3D 4.1 simulation. --- src/gallium/drivers/vc5/vc5_context.h | 20 ++++++++++-- src/gallium/drivers/vc5/vc5_draw.c | 47 +++++++++++++++++++++++++-- src/gallium/drivers/vc5/vc5_emit.c | 9 +++-- src/gallium/drivers/vc5/vc5_rcl.c | 16 ++++++++- src/gallium/drivers/vc5/vc5_state.c | 40 ++++++++++++++++------- 5 files changed, 111 insertions(+), 21 deletions(-) diff --git a/src/gallium/drivers/vc5/vc5_context.h b/src/gallium/drivers/vc5/vc5_context.h index f6ed91c27ae..f61c37ba924 100644 --- a/src/gallium/drivers/vc5/vc5_context.h +++ b/src/gallium/drivers/vc5/vc5_context.h @@ -199,6 +199,13 @@ struct vc5_job_key { struct pipe_surface *zsbuf; }; +enum vc5_ez_state { + VC5_EZ_UNDECIDED = 0, + VC5_EZ_GT_GE, + VC5_EZ_LT_LE, + VC5_EZ_DISABLED, +}; + /** * A complete bin/render job. * @@ -300,7 +307,16 @@ struct vc5_job { */ bool tf_enabled; - bool uses_early_z; + /** + * Current EZ state for drawing. Updated at the start of draw after + * we've decided on the shader being rendered. + */ + enum vc5_ez_state ez_state; + /** + * The first EZ state that was used for drawing with a decided EZ + * direction (so either UNDECIDED, GT, or LT). + */ + enum vc5_ez_state first_ez_state; /** * Number of draw calls (not counting full buffer clears) queued in @@ -429,7 +445,7 @@ struct vc5_rasterizer_state { struct vc5_depth_stencil_alpha_state { struct pipe_depth_stencil_alpha_state base; - bool early_z_enable; + enum vc5_ez_state ez_state; /** Uniforms for stencil state. * diff --git a/src/gallium/drivers/vc5/vc5_draw.c b/src/gallium/drivers/vc5/vc5_draw.c index 7a409c14d4c..25f4883be2d 100644 --- a/src/gallium/drivers/vc5/vc5_draw.c +++ b/src/gallium/drivers/vc5/vc5_draw.c @@ -326,6 +326,49 @@ vc5_tf_statistics_record(struct vc5_context *vc5, } } +static void +vc5_update_job_ez(struct vc5_context *vc5, struct vc5_job *job) +{ + switch (vc5->zsa->ez_state) { + case VC5_EZ_UNDECIDED: + /* If the Z/S state didn't pick a direction but didn't + * disable, then go along with the current EZ state. This + * allows EZ optimization for Z func == EQUAL or NEVER. + */ + break; + + case VC5_EZ_LT_LE: + case VC5_EZ_GT_GE: + /* If the Z/S state picked a direction, then it needs to match + * the current direction if we've decided on one. + */ + if (job->ez_state == VC5_EZ_UNDECIDED) + job->ez_state = vc5->zsa->ez_state; + else if (job->ez_state != vc5->zsa->ez_state) + job->ez_state = VC5_EZ_DISABLED; + break; + + case VC5_EZ_DISABLED: + /* If the current Z/S state disables EZ because of a bad Z + * func or stencil operation, then we can't do any more EZ in + * this frame. + */ + job->ez_state = VC5_EZ_DISABLED; + break; + } + + /* If the FS affects the Z of the pixels, then it may update against + * the chosen EZ direction (though we could use + * ARB_conservative_depth's hints to avoid this) + */ + if (vc5->prog.fs->prog_data.fs->writes_z) { + job->ez_state = VC5_EZ_DISABLED; + } + + if (job->first_ez_state == VC5_EZ_UNDECIDED) + job->first_ez_state = job->ez_state; +} + static void vc5_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) { @@ -384,6 +427,7 @@ vc5_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) vc5_start_draw(vc5); vc5_update_compiled_shaders(vc5, info->mode); + vc5_update_job_ez(vc5, job); #if V3D_VERSION >= 41 v3d41_emit_state(pctx); @@ -515,9 +559,6 @@ vc5_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) if (vc5->zsa->base.depth.enabled) { job->resolve |= PIPE_CLEAR_DEPTH; rsc->initialized_buffers = PIPE_CLEAR_DEPTH; - - if (vc5->zsa->early_z_enable) - job->uses_early_z = true; } if (vc5->zsa->base.stencil[0].enabled) { diff --git a/src/gallium/drivers/vc5/vc5_emit.c b/src/gallium/drivers/vc5/vc5_emit.c index d5bf2824d29..71f508c9ee8 100644 --- a/src/gallium/drivers/vc5/vc5_emit.c +++ b/src/gallium/drivers/vc5/vc5_emit.c @@ -382,13 +382,16 @@ v3dX(emit_state)(struct pipe_context *pctx) config.blend_enable = vc5->blend->rt[0].blend_enable; - config.early_z_updates_enable = true; + /* Note: EZ state may update based on the compiled FS, + * along with ZSA + */ + config.early_z_updates_enable = + (job->ez_state != VC5_EZ_DISABLED); if (vc5->zsa->base.depth.enabled) { config.z_updates_enable = vc5->zsa->base.depth.writemask; config.early_z_enable = - (vc5->zsa->early_z_enable && - !vc5->prog.fs->prog_data.fs->writes_z); + config.early_z_updates_enable; config.depth_test_function = vc5->zsa->base.depth.func; } else { diff --git a/src/gallium/drivers/vc5/vc5_rcl.c b/src/gallium/drivers/vc5/vc5_rcl.c index a5efa32e215..8ff1515f883 100644 --- a/src/gallium/drivers/vc5/vc5_rcl.c +++ b/src/gallium/drivers/vc5/vc5_rcl.c @@ -481,7 +481,21 @@ v3dX(emit_rcl)(struct vc5_job *job) /* XXX: Early D/S clear */ - config.early_z_disable = !job->uses_early_z; + switch (job->first_ez_state) { + case VC5_EZ_UNDECIDED: + case VC5_EZ_LT_LE: + config.early_z_disable = false; + config.early_z_test_and_update_direction = + EARLY_Z_DIRECTION_LT_LE; + break; + case VC5_EZ_GT_GE: + config.early_z_disable = false; + config.early_z_test_and_update_direction = + EARLY_Z_DIRECTION_GT_GE; + break; + case VC5_EZ_DISABLED: + config.early_z_disable = true; + } config.image_width_pixels = job->draw_width; config.image_height_pixels = job->draw_height; diff --git a/src/gallium/drivers/vc5/vc5_state.c b/src/gallium/drivers/vc5/vc5_state.c index 75cd948e4a3..ba2d748ba94 100644 --- a/src/gallium/drivers/vc5/vc5_state.c +++ b/src/gallium/drivers/vc5/vc5_state.c @@ -158,19 +158,35 @@ vc5_create_depth_stencil_alpha_state(struct pipe_context *pctx, so->base = *cso; if (cso->depth.enabled) { - /* We only handle early Z in the < direction because otherwise - * we'd have to runtime guess which direction to set in the - * render config. + switch (cso->depth.func) { + case PIPE_FUNC_LESS: + case PIPE_FUNC_LEQUAL: + so->ez_state = VC5_EZ_LT_LE; + break; + case PIPE_FUNC_GREATER: + case PIPE_FUNC_GEQUAL: + so->ez_state = VC5_EZ_GT_GE; + break; + case PIPE_FUNC_NEVER: + case PIPE_FUNC_EQUAL: + so->ez_state = VC5_EZ_UNDECIDED; + break; + default: + so->ez_state = VC5_EZ_DISABLED; + break; + } + + /* If stencil is enabled and it's not a no-op, then it would + * break EZ updates. */ - so->early_z_enable = - ((cso->depth.func == PIPE_FUNC_LESS || - cso->depth.func == PIPE_FUNC_LEQUAL) && - (!cso->stencil[0].enabled || - (cso->stencil[0].zfail_op == PIPE_STENCIL_OP_KEEP && - cso->stencil[0].func == PIPE_FUNC_ALWAYS && - (!cso->stencil[1].enabled || - (cso->stencil[1].zfail_op == PIPE_STENCIL_OP_KEEP && - cso->stencil[1].func == PIPE_FUNC_ALWAYS))))); + if (cso->stencil[0].enabled && + (cso->stencil[0].zfail_op != PIPE_STENCIL_OP_KEEP || + cso->stencil[0].func != PIPE_FUNC_ALWAYS || + (cso->stencil[1].enabled && + (cso->stencil[1].zfail_op != PIPE_STENCIL_OP_KEEP && + cso->stencil[1].func != PIPE_FUNC_ALWAYS)))) { + so->ez_state = VC5_EZ_DISABLED; + } } const struct pipe_stencil_state *front = &cso->stencil[0]; -- 2.30.2