mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-05 09:00:08 +01:00
radv: Fix a hang on CB change by adding flushes.
This workaround fixes a hang while loading a renderdoc trace for me. Since the workload does 1 mip per cmdbuffer it is quite hard to confirm what exactly the conditions for the hang are but this is the most restrictive set I found and it corresponds to a workaround in AMDVLK as well. CC: mesa-stable Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7210>
This commit is contained in:
parent
8564715253
commit
4cce4d22a7
2 changed files with 76 additions and 0 deletions
|
|
@ -2236,6 +2236,71 @@ radv_load_color_clear_metadata(struct radv_cmd_buffer *cmd_buffer,
|
|||
}
|
||||
}
|
||||
|
||||
/* GFX9+ metadata cache flushing workaround. metadata cache coherency is
|
||||
* broken if the CB caches data of multiple mips of the same image at the
|
||||
* same time.
|
||||
*
|
||||
* Insert some flushes to avoid this.
|
||||
*/
|
||||
static void
|
||||
radv_emit_fb_mip_change_flush(struct radv_cmd_buffer *cmd_buffer)
|
||||
{
|
||||
struct radv_framebuffer *framebuffer = cmd_buffer->state.framebuffer;
|
||||
const struct radv_subpass *subpass = cmd_buffer->state.subpass;
|
||||
bool color_mip_changed = false;
|
||||
|
||||
/* Entire workaround is not applicable before GFX9 */
|
||||
if (cmd_buffer->device->physical_device->rad_info.chip_class < GFX9)
|
||||
return;
|
||||
|
||||
if (!framebuffer)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < subpass->color_count; ++i) {
|
||||
int idx = subpass->color_attachments[i].attachment;
|
||||
struct radv_image_view *iview = cmd_buffer->state.attachments[idx].iview;
|
||||
|
||||
if ((radv_image_has_CB_metadata(iview->image) ||
|
||||
radv_image_has_dcc(iview->image)) &&
|
||||
cmd_buffer->state.cb_mip[i] != iview->base_mip)
|
||||
color_mip_changed = true;
|
||||
|
||||
cmd_buffer->state.cb_mip[i] = iview->base_mip;
|
||||
}
|
||||
|
||||
if (color_mip_changed) {
|
||||
cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
|
||||
RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function does the flushes for mip changes if the levels are not zero for
|
||||
* all render targets. This way we can assume at the start of the next cmd_buffer
|
||||
* that rendering to mip 0 doesn't need any flushes. As that is the most common
|
||||
* case that saves some flushes. */
|
||||
static void
|
||||
radv_emit_mip_change_flush_default(struct radv_cmd_buffer *cmd_buffer)
|
||||
{
|
||||
/* Entire workaround is not applicable before GFX9 */
|
||||
if (cmd_buffer->device->physical_device->rad_info.chip_class < GFX9)
|
||||
return;
|
||||
|
||||
bool need_color_mip_flush = false;
|
||||
for (unsigned i = 0; i < 8; ++i) {
|
||||
if (cmd_buffer->state.cb_mip[i]) {
|
||||
need_color_mip_flush = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_color_mip_flush) {
|
||||
cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
|
||||
RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
|
||||
}
|
||||
|
||||
memset(cmd_buffer->state.cb_mip, 0, sizeof(cmd_buffer->state.cb_mip));
|
||||
}
|
||||
|
||||
static void
|
||||
radv_emit_framebuffer_state(struct radv_cmd_buffer *cmd_buffer)
|
||||
{
|
||||
|
|
@ -4075,6 +4140,8 @@ VkResult radv_EndCommandBuffer(
|
|||
{
|
||||
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
|
||||
radv_emit_mip_change_flush_default(cmd_buffer);
|
||||
|
||||
if (cmd_buffer->queue_family_index != RADV_QUEUE_TRANSFER) {
|
||||
if (cmd_buffer->device->physical_device->rad_info.chip_class == GFX6)
|
||||
cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_CS_PARTIAL_FLUSH | RADV_CMD_FLAG_PS_PARTIAL_FLUSH | RADV_CMD_FLAG_WB_L2;
|
||||
|
|
@ -4655,6 +4722,8 @@ void radv_CmdExecuteCommands(
|
|||
|
||||
assert(commandBufferCount > 0);
|
||||
|
||||
radv_emit_mip_change_flush_default(primary);
|
||||
|
||||
/* Emit pending flushes on primary prior to executing secondary */
|
||||
si_emit_cache_flush(primary);
|
||||
|
||||
|
|
@ -4687,6 +4756,7 @@ void radv_CmdExecuteCommands(
|
|||
* has been recorded without a framebuffer, otherwise
|
||||
* fast color/depth clears can't work.
|
||||
*/
|
||||
radv_emit_fb_mip_change_flush(primary);
|
||||
radv_emit_framebuffer_state(primary);
|
||||
}
|
||||
|
||||
|
|
@ -5294,6 +5364,10 @@ radv_draw(struct radv_cmd_buffer *cmd_buffer,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Need to apply this workaround early as it can set flush flags. */
|
||||
if (cmd_buffer->state.dirty & RADV_CMD_DIRTY_FRAMEBUFFER)
|
||||
radv_emit_fb_mip_change_flush(cmd_buffer);
|
||||
|
||||
/* Use optimal packet order based on whether we need to sync the
|
||||
* pipeline.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1391,6 +1391,8 @@ struct radv_cmd_state {
|
|||
uint32_t num_layout_transitions;
|
||||
bool pending_sqtt_barrier_end;
|
||||
enum rgp_flush_bits sqtt_flush_bits;
|
||||
|
||||
uint8_t cb_mip[MAX_RTS];
|
||||
};
|
||||
|
||||
struct radv_cmd_pool {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue