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.
*
*/
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
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.
*
}
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)
{
struct vc5_context *vc5 = vc5_context(pctx);
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);
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) {
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 {
/* 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;
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];