diff --git a/src/freedreno/registers/a6xx.xml b/src/freedreno/registers/a6xx.xml
index c7b83059eb8..0a0eec3ea07 100644
--- a/src/freedreno/registers/a6xx.xml
+++ b/src/freedreno/registers/a6xx.xml
@@ -891,6 +891,44 @@ to upconvert to 32b float internally?
+
+ Allow early z-test and early-lrz (if applicable)
+
+ Disable early z-test and early-lrz test (if applicable)
+
+
+ A special mode that allows early-lrz test but disables
+ early-z test. Which might sound a bit funny, since
+ lrz-test happens before z-test. But as long as a couple
+ conditions are maintained this allows using lrz-test in
+ cases where fragment shader has kill/discard:
+
+ 1) Disable lrz-write in cases where it is uncertain during
+ binning pass that a fragment will pass. Ie. if frag
+ shader has-kill, writes-z, or alpha/stencil test is
+ enabled. (For correctness, lrz-write must be disabled
+ when blend is enabled.) This is analogous to how a
+ z-prepass works.
+
+ 2) Disable lrz-write and test if a depth-test direction
+ reversal is detected. Due to condition (1), the contents
+ of the lrz buffer are a conservative estimation of the
+ depth buffer during the draw pass. Meaning that geometry
+ that we know for certain will not be visible will not pass
+ lrz-test. But geometry which may be (or contributes to
+ blend) will pass the lrz-test.
+
+ This allows us to keep early-lrz-test in cases where the frag
+ shader does not write-z (ie. we know the z-value before FS)
+ and does not have side-effects (image/ssbo writes, etc), but
+ does have kill/discard. Which turns out to be a common
+ enough case that it is useful to keep early-lrz test against
+ the conservative lrz buffer to discard fragments that we
+ know will definitely not be visible.
+
+
+
+
@@ -1909,7 +1947,7 @@ to upconvert to 32b float internally?
-
+
@@ -2259,7 +2297,7 @@ to upconvert to 32b float internally?
-
+
diff --git a/src/freedreno/vulkan/tu_pipeline.c b/src/freedreno/vulkan/tu_pipeline.c
index debc4811e32..5002f9f6f2a 100644
--- a/src/freedreno/vulkan/tu_pipeline.c
+++ b/src/freedreno/vulkan/tu_pipeline.c
@@ -1383,18 +1383,19 @@ tu6_emit_fs_outputs(struct tu_cs *cs,
tu_cs_emit_regs(cs,
A6XX_RB_RENDER_COMPONENTS(.dword = render_components));
- uint32_t gras_su_depth_plane_cntl = 0;
- uint32_t rb_depth_plane_cntl = 0;
+ enum a6xx_ztest_mode zmode;
+
if (fs->no_earlyz || fs->has_kill || fs->writes_pos) {
- gras_su_depth_plane_cntl |= A6XX_GRAS_SU_DEPTH_PLANE_CNTL_FRAG_WRITES_Z;
- rb_depth_plane_cntl |= A6XX_RB_DEPTH_PLANE_CNTL_FRAG_WRITES_Z;
+ zmode = A6XX_LATE_Z;
+ } else {
+ zmode = A6XX_EARLY_Z;
}
tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SU_DEPTH_PLANE_CNTL, 1);
- tu_cs_emit(cs, gras_su_depth_plane_cntl);
+ tu_cs_emit(cs, A6XX_GRAS_SU_DEPTH_PLANE_CNTL_Z_MODE(zmode));
tu_cs_emit_pkt4(cs, REG_A6XX_RB_DEPTH_PLANE_CNTL, 1);
- tu_cs_emit(cs, rb_depth_plane_cntl);
+ tu_cs_emit(cs, A6XX_RB_DEPTH_PLANE_CNTL_Z_MODE(zmode));
}
static void
diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_program.c b/src/gallium/drivers/freedreno/a6xx/fd6_program.c
index 45a05544e6b..dad117688af 100644
--- a/src/gallium/drivers/freedreno/a6xx/fd6_program.c
+++ b/src/gallium/drivers/freedreno/a6xx/fd6_program.c
@@ -835,13 +835,19 @@ setup_stateobj(struct fd_ringbuffer *ring, struct fd_screen *screen,
OUT_RING(ring,
COND(primid_passthru, A6XX_VFD_CONTROL_6_PRIMID_PASSTHRU)); /* VFD_CONTROL_6 */
- bool fragz = fs->no_earlyz || fs->has_kill || fs->writes_pos;
+ enum a6xx_ztest_mode zmode;
+
+ if (fs->no_earlyz || fs->has_kill || fs->writes_pos) {
+ zmode = A6XX_LATE_Z;
+ } else {
+ zmode = A6XX_EARLY_Z;
+ }
OUT_PKT4(ring, REG_A6XX_RB_DEPTH_PLANE_CNTL, 1);
- OUT_RING(ring, COND(fragz, A6XX_RB_DEPTH_PLANE_CNTL_FRAG_WRITES_Z));
+ OUT_RING(ring, A6XX_RB_DEPTH_PLANE_CNTL_Z_MODE(zmode));
OUT_PKT4(ring, REG_A6XX_GRAS_SU_DEPTH_PLANE_CNTL, 1);
- OUT_RING(ring, COND(fragz, A6XX_GRAS_SU_DEPTH_PLANE_CNTL_FRAG_WRITES_Z));
+ OUT_RING(ring, A6XX_GRAS_SU_DEPTH_PLANE_CNTL_Z_MODE(zmode));
if (!binning_pass)
fd6_emit_immediates(screen, fs, ring);