tu: Disable LRZ writes after most stencil-write operations.
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

As explained in the comment, stencil can have a similar dependency on
later LRZ writes to how blending does.  Fixes
dEQP-VK.imageless_framebuffer.depth_stencil with TU_DEBUG=gmem,forcebin
(so you get LRZ filled during binning of the single draw call that
happened)

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/13533
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36660>
This commit is contained in:
Emma Anholt 2025-08-07 17:04:00 -07:00 committed by Marge Bot
parent 07cee75c39
commit 071a7e5f8f
3 changed files with 49 additions and 0 deletions

View file

@ -6225,6 +6225,31 @@ tu6_stencil_written_on_depth_fail(
}
}
/* Returns true if the stencil write result may change based on the result of a
* depth test.
*/
static bool
tu6_stencil_written_based_on_depth_test(
const struct vk_stencil_test_face_state *face)
{
switch (face->op.compare) {
case VK_COMPARE_OP_ALWAYS:
/* The stencil op always passes, no need to worry about failOp. */
return face->op.depth_fail != VK_STENCIL_OP_KEEP ||
face->op.pass != VK_STENCIL_OP_KEEP;
case VK_COMPARE_OP_NEVER:
/* The stencil op always fails, so failOp will always be used. */
return face->op.fail != VK_STENCIL_OP_KEEP;
default:
/* If the stencil test fails, depth may fail as well, so we can write
* stencil when the depth fails if failOp is not VK_STENCIL_OP_KEEP.
*/
return face->op.fail != VK_STENCIL_OP_KEEP ||
face->op.pass != VK_STENCIL_OP_KEEP ||
face->op.depth_fail != VK_STENCIL_OP_KEEP;
}
}
/* Various frontends (ANGLE, zink at least) will enable stencil testing with
* what works out to be no-op writes. Simplify what they give us into flags
* that LRZ can use.
@ -6240,6 +6265,7 @@ tu6_update_simplified_stencil_state(struct tu_cmd_buffer *cmd)
cmd->state.stencil_front_write = false;
cmd->state.stencil_back_write = false;
cmd->state.stencil_written_on_depth_fail = false;
cmd->state.stencil_written_based_on_depth_test = false;
return;
}
@ -6272,6 +6298,11 @@ tu6_update_simplified_stencil_state(struct tu_cmd_buffer *cmd)
tu6_stencil_written_on_depth_fail(&ds->stencil.front)) ||
(cmd->state.stencil_back_write &&
tu6_stencil_written_on_depth_fail(&ds->stencil.back));
cmd->state.stencil_written_based_on_depth_test =
(cmd->state.stencil_front_write &&
tu6_stencil_written_based_on_depth_test(&ds->stencil.front)) ||
(cmd->state.stencil_back_write &&
tu6_stencil_written_based_on_depth_test(&ds->stencil.back));
}
static bool

View file

@ -549,6 +549,7 @@ struct tu_cmd_state
bool stencil_front_write;
bool stencil_back_write;
bool stencil_written_on_depth_fail;
bool stencil_written_based_on_depth_test;
bool pipeline_sysmem_single_prim_mode;
bool pipeline_has_tess;
bool pipeline_disable_gmem;

View file

@ -964,6 +964,23 @@ tu6_calculate_lrz_state(struct tu_cmd_buffer *cmd,
}
}
/* If the stencil test behavior depends on the result of the depth test, we
* have to skip LRZ for the rest of the RP for basically the same reason as
* the blending case above (LRZ testing enabled on previous draws may result
* in skipping their Z changes which feed into this draw, so we can't let
* later Z writes affect any of them).
*
* Because the LRZ test runs first, failing the LRZ test may result in
* skipping the stencil test and subsequent stencil write. This is ok if
* stencil is only written when the depth test passes, because then the LRZ
* test will also pass, but if it may be written when the depth or stencil
* test fails then we need to disable the LRZ test for the draw as well.
*/
if (cmd->state.stencil_written_based_on_depth_test) {
tu_lrz_write_disable_reason(cmd, "stencil write based on depth test");
cmd->state.lrz.disable_write_for_rp = true;
}
if (disable_lrz)
cmd->state.lrz.valid = false;