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.
This commit is contained in:
Eric Anholt 2018-03-23 16:18:02 -07:00
parent 262208eb3c
commit 1bf466270d
5 changed files with 111 additions and 21 deletions

View file

@ -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.
*

View file

@ -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) {

View file

@ -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 {

View file

@ -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;

View file

@ -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];