anv: Only flush render target cache when detecting RT changes

We setup an empty render target when there are no color attachments,
which effectively makes it a different surface state. In most cases
the compiler will insert a null-rt bit in the extended descriptor
which means the RT isn't even accessed. But in some cases like
alpha-to-coverage output + depth/stencil write, we will access the
render target because using the null-rt will prevent alpha-to-coverage
from happening.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 2bd304bc8f ("anv: Skip the RT flush when doing depth-only rendering.")
Reviewed-by: Ivan Briano <ivan.briano@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31196>
This commit is contained in:
Lionel Landwerlin 2024-09-18 13:50:18 +03:00 committed by Marge Bot
parent fb3ae17d96
commit badb3f6301
3 changed files with 84 additions and 18 deletions

View file

@ -3822,6 +3822,12 @@ struct anv_cmd_graphics_state {
struct anv_attachment stencil_att;
struct anv_state null_surface_state;
/* Bitfield of color attachments disabled by a pipeline (pointing a null
* surface state in the last emitted binding table for the fragment
* stage)
*/
uint8_t disabled_color_atts;
anv_cmd_dirty_mask_t dirty;
uint32_t vb_dirty;

View file

@ -5176,15 +5176,24 @@ void genX(CmdBeginRendering)(
};
const uint32_t color_att_count = pRenderingInfo->colorAttachmentCount;
result = anv_cmd_buffer_init_attachments(cmd_buffer, color_att_count);
if (result != VK_SUCCESS)
return;
genX(flush_pipeline_select_3d)(cmd_buffer);
UNUSED bool render_target_change = false;
for (uint32_t i = 0; i < gfx->color_att_count; i++) {
if (pRenderingInfo->pColorAttachments[i].imageView == VK_NULL_HANDLE)
if (pRenderingInfo->pColorAttachments[i].imageView == VK_NULL_HANDLE) {
render_target_change |= gfx->color_att[i].iview != NULL;
gfx->color_att[i].vk_format = VK_FORMAT_UNDEFINED;
gfx->color_att[i].iview = NULL;
gfx->color_att[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
gfx->color_att[i].aux_usage = ISL_AUX_USAGE_NONE;
continue;
}
const VkRenderingAttachmentInfo *att =
&pRenderingInfo->pColorAttachments[i];
@ -5211,6 +5220,13 @@ void genX(CmdBeginRendering)(
att->imageLayout,
cmd_buffer->queue_family->queueFlags);
render_target_change |= gfx->color_att[i].iview != iview;
gfx->color_att[i].vk_format = iview->vk.format;
gfx->color_att[i].iview = iview;
gfx->color_att[i].layout = att->imageLayout;
gfx->color_att[i].aux_usage = aux_usage;
union isl_color_value fast_clear_color = { .u32 = { 0, } };
if (att->loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR &&
@ -5325,11 +5341,6 @@ void genX(CmdBeginRendering)(
assert(att->imageLayout == initial_layout);
}
gfx->color_att[i].vk_format = iview->vk.format;
gfx->color_att[i].iview = iview;
gfx->color_att[i].layout = att->imageLayout;
gfx->color_att[i].aux_usage = aux_usage;
struct isl_view isl_view = iview->planes[0].isl;
if (pRenderingInfo->viewMask) {
assert(isl_view.array_len >= util_last_bit(pRenderingInfo->viewMask));
@ -5606,14 +5617,7 @@ void genX(CmdBeginRendering)(
gfx->dirty |= ANV_CMD_DIRTY_PIPELINE;
#if GFX_VER >= 11
bool has_color_att = false;
for (uint32_t i = 0; i < gfx->color_att_count; i++) {
if (pRenderingInfo->pColorAttachments[i].imageView != VK_NULL_HANDLE) {
has_color_att = true;
break;
}
}
if (has_color_att) {
if (render_target_change) {
/* The PIPE_CONTROL command description says:
*
* "Whenever a Binding Table Index (BTI) used by a Render Target Message

View file

@ -687,6 +687,60 @@ genX(emit_ds)(struct anv_cmd_buffer *cmd_buffer)
#endif
}
ALWAYS_INLINE static void
cmd_buffer_maybe_flush_rt_writes(struct anv_cmd_buffer *cmd_buffer,
struct anv_graphics_pipeline *pipeline)
{
#if GFX_VER >= 11
if (!anv_pipeline_has_stage(pipeline, MESA_SHADER_FRAGMENT))
return;
const struct anv_shader_bin *shader =
pipeline->base.shaders[MESA_SHADER_FRAGMENT];
const struct anv_pipeline_bind_map *bind_map = &shader->bind_map;
unsigned s;
uint8_t disabled_mask = 0;
for (s = 0; s < bind_map->surface_count; s++) {
const struct anv_pipeline_binding *binding =
&bind_map->surface_to_descriptor[s];
if (binding->set != ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS)
break;
if (binding->index >= cmd_buffer->state.gfx.color_att_count)
disabled_mask |= BITFIELD_BIT(s);
}
const uint8_t diff_mask = (1u << s) - 1;
if ((cmd_buffer->state.gfx.disabled_color_atts & diff_mask) != disabled_mask) {
cmd_buffer->state.gfx.disabled_color_atts = disabled_mask |
(cmd_buffer->state.gfx.disabled_color_atts & ~diff_mask);
/* The PIPE_CONTROL command description says:
*
* "Whenever a Binding Table Index (BTI) used by a Render Target Message
* points to a different RENDER_SURFACE_STATE, SW must issue a Render
* Target Cache Flush by enabling this bit. When render target flush
* is set due to new association of BTI, PS Scoreboard Stall bit must
* be set in this packet."
*
* Within a renderpass, the render target entries in the binding tables
* remain the same as what was setup at CmdBeginRendering() with one
* exception where have to setup a null render target because a fragment
* writes only depth/stencil yet the renderpass has been setup with at
* least one color attachment. This is because our render target messages
* in the shader always send the color.
*/
anv_add_pending_pipe_bits(cmd_buffer,
ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT |
ANV_PIPE_STALL_AT_SCOREBOARD_BIT,
"change RT due to shader outputs");
}
#endif
}
ALWAYS_INLINE static void
genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer)
{
@ -708,16 +762,18 @@ genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer)
genX(flush_pipeline_select_3d)(cmd_buffer);
/* Wa_14015814527
*
* Apply task URB workaround when switching from task to primitive.
*/
if (cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_PIPELINE) {
/* Wa_14015814527
*
* Apply task URB workaround when switching from task to primitive.
*/
if (anv_pipeline_is_primitive(pipeline)) {
genX(apply_task_urb_workaround)(cmd_buffer);
} else if (anv_pipeline_has_stage(pipeline, MESA_SHADER_TASK)) {
cmd_buffer->state.gfx.used_task_shader = true;
}
cmd_buffer_maybe_flush_rt_writes(cmd_buffer, pipeline);
}
/* Apply any pending pipeline flushes we may have. We want to apply them