diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c index 667fa7402b5..644b607124c 100644 --- a/src/broadcom/vulkan/v3dv_cmd_buffer.c +++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c @@ -970,13 +970,17 @@ cmd_buffer_subpass_handle_pending_resolves(struct v3dv_cmd_buffer *cmd_buffer) if (src_attachment_idx == VK_ATTACHMENT_UNUSED) continue; - if (pass->attachments[src_attachment_idx].use_tlb_resolve) + /* Skip if this attachment doesn't have a resolve or if it was already + * implemented as a TLB resolve. + */ + if (!cmd_buffer->state.attachments[src_attachment_idx].has_resolve || + cmd_buffer->state.attachments[src_attachment_idx].use_tlb_resolve) { continue; + } const uint32_t dst_attachment_idx = subpass->resolve_attachments[i].attachment; - if (dst_attachment_idx == VK_ATTACHMENT_UNUSED) - continue; + assert(dst_attachment_idx != VK_ATTACHMENT_UNUSED); struct v3dv_image_view *src_iview = cmd_buffer->state.attachments[src_attachment_idx].image_view; @@ -1162,6 +1166,48 @@ cmd_buffer_update_tile_alignment(struct v3dv_cmd_buffer *cmd_buffer) } } +static void +cmd_buffer_update_attachment_resolve_state(struct v3dv_cmd_buffer *cmd_buffer) +{ + /* NOTE: This should be called after cmd_buffer_update_tile_alignment() + * since it relies on up-to-date information about subpass tile alignment. + */ + const struct v3dv_cmd_buffer_state *state = &cmd_buffer->state; + const struct v3dv_render_pass *pass = state->pass; + const struct v3dv_subpass *subpass = &pass->subpasses[state->subpass_idx]; + + for (uint32_t i = 0; i < subpass->color_count; i++) { + const uint32_t attachment_idx = subpass->color_attachments[i].attachment; + if (attachment_idx == VK_ATTACHMENT_UNUSED) + continue; + + state->attachments[attachment_idx].has_resolve = + subpass->resolve_attachments && + subpass->resolve_attachments[i].attachment != VK_ATTACHMENT_UNUSED; + + state->attachments[attachment_idx].use_tlb_resolve = + state->attachments[attachment_idx].has_resolve && + state->tile_aligned_render_area && + pass->attachments[attachment_idx].try_tlb_resolve; + } + + uint32_t ds_attachment_idx = subpass->ds_attachment.attachment; + if (ds_attachment_idx != VK_ATTACHMENT_UNUSED) { + uint32_t ds_resolve_attachment_idx = + subpass->ds_resolve_attachment.attachment; + state->attachments[ds_attachment_idx].has_resolve = + ds_resolve_attachment_idx != VK_ATTACHMENT_UNUSED; + + assert(!state->attachments[ds_attachment_idx].has_resolve || + (subpass->resolve_depth || subpass->resolve_stencil)); + + state->attachments[ds_attachment_idx].use_tlb_resolve = + state->attachments[ds_attachment_idx].has_resolve && + state->tile_aligned_render_area && + pass->attachments[ds_attachment_idx].try_tlb_resolve; + } +} + static void cmd_buffer_state_set_attachment_clear_color(struct v3dv_cmd_buffer *cmd_buffer, uint32_t attachment_idx, @@ -1556,6 +1602,8 @@ v3dv_cmd_buffer_subpass_start(struct v3dv_cmd_buffer *cmd_buffer, */ cmd_buffer_update_tile_alignment(cmd_buffer); + cmd_buffer_update_attachment_resolve_state(cmd_buffer); + /* If we can't use TLB clears then we need to emit draw clears for any * LOAD_OP_CLEAR attachments in this subpass now. We might also need to emit * Depth/Stencil clears if we hit GFXH-1461. diff --git a/src/broadcom/vulkan/v3dv_pass.c b/src/broadcom/vulkan/v3dv_pass.c index 7ba144f5aa4..99d37281ce6 100644 --- a/src/broadcom/vulkan/v3dv_pass.c +++ b/src/broadcom/vulkan/v3dv_pass.c @@ -33,11 +33,11 @@ num_subpass_attachments(const VkSubpassDescription2 *desc) } static void -set_use_tlb_resolve(struct v3dv_device *device, +set_try_tlb_resolve(struct v3dv_device *device, struct v3dv_render_pass_attachment *att) { const struct v3dv_format *format = v3dv_X(device, get_format)(att->desc.format); - att->use_tlb_resolve = v3dv_X(device, format_supports_tlb_resolve)(format); + att->try_tlb_resolve = v3dv_X(device, format_supports_tlb_resolve)(format); } static void @@ -82,7 +82,7 @@ pass_find_subpass_range_for_attachments(struct v3dv_device *device, if (subpass->resolve_attachments && subpass->resolve_attachments[j].attachment != VK_ATTACHMENT_UNUSED) { - set_use_tlb_resolve(device, att); + set_try_tlb_resolve(device, att); } } @@ -94,7 +94,7 @@ pass_find_subpass_range_for_attachments(struct v3dv_device *device, pass->attachments[ds_attachment_idx].last_subpass = i; if (subpass->ds_resolve_attachment.attachment != VK_ATTACHMENT_UNUSED) - set_use_tlb_resolve(device, &pass->attachments[ds_attachment_idx]); + set_try_tlb_resolve(device, &pass->attachments[ds_attachment_idx]); } for (uint32_t j = 0; j < subpass->input_count; j++) { diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index 94d59234dab..0525f500dab 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -727,10 +727,11 @@ struct v3dv_render_pass_attachment { uint32_t last_subpass; } views[MAX_MULTIVIEW_VIEW_COUNT]; - /* If this is a multismapled attachment that is going to be resolved, - * whether we can use the TLB resolve on store. + /* If this is a multisampled attachment that is going to be resolved, + * whether we may be able to use the TLB hardware resolve based on the + * attachment format. */ - bool use_tlb_resolve; + bool try_tlb_resolve; }; struct v3dv_render_pass { @@ -847,6 +848,14 @@ struct v3dv_cmd_buffer_attachment_state { * framebuffer is used, from VkRenderPassAttachmentBeginInfo. */ struct v3dv_image_view *image_view; + + /* If this is a multisampled attachment with a resolve operation. */ + bool has_resolve; + + /* If this is a multisampled attachment with a resolve operation, + * whether we can use the TLB for the resolve. + */ + bool use_tlb_resolve; }; struct v3dv_viewport_state { diff --git a/src/broadcom/vulkan/v3dvx_cmd_buffer.c b/src/broadcom/vulkan/v3dvx_cmd_buffer.c index ce6afcf5ee4..f0a64a48a7c 100644 --- a/src/broadcom/vulkan/v3dvx_cmd_buffer.c +++ b/src/broadcom/vulkan/v3dvx_cmd_buffer.c @@ -502,8 +502,11 @@ cmd_buffer_render_pass_emit_stores(struct v3dv_cmd_buffer *cmd_buffer, ds_attachment->desc.stencilStoreOp); /* If we have a resolve, handle it before storing the tile */ - if (subpass->resolve_depth || subpass->resolve_stencil) { - assert(ds_attachment->use_tlb_resolve); + const struct v3dv_cmd_buffer_attachment_state *ds_att_state = + &state->attachments[ds_attachment_idx]; + if (ds_att_state->use_tlb_resolve) { + assert(ds_att_state->has_resolve); + assert(subpass->resolve_depth || subpass->resolve_stencil); const uint32_t resolve_attachment_idx = subpass->ds_resolve_attachment.attachment; assert(resolve_attachment_idx != VK_ATTACHMENT_UNUSED); @@ -515,6 +518,12 @@ cmd_buffer_render_pass_emit_stores(struct v3dv_cmd_buffer *cmd_buffer, zs_buffer, false, false); has_stores = true; + } else if (ds_att_state->has_resolve) { + /* If we can't use the TLB to implement the resolve we will need to + * store the attachment so we can implement it later using a blit. + */ + needs_depth_store = subpass->resolve_depth; + needs_stencil_store = subpass->resolve_stencil; } /* GFXH-1689: The per-buffer store command's clear buffer bit is broken @@ -593,15 +602,16 @@ cmd_buffer_render_pass_emit_stores(struct v3dv_cmd_buffer *cmd_buffer, * color attachment store below, since the clear happens after the * store is completed. * - * If the attachment doesn't support TLB resolves then we will have to - * fallback to doing the resolve in a shader separately after this - * job, so we will need to store the multisampled sttachment even if that - * wansn't requested by the client. + * If the attachment doesn't support TLB resolves (or the render area + * is not aligned to tile boundaries) then we will have to fallback to + * doing the resolve in a shader separately after this job, so we will + * need to store the multisampled attachment even if that wasn't + * requested by the client. */ - const bool needs_resolve = - subpass->resolve_attachments && - subpass->resolve_attachments[i].attachment != VK_ATTACHMENT_UNUSED; - if (needs_resolve && attachment->use_tlb_resolve) { + const struct v3dv_cmd_buffer_attachment_state *att_state = + &state->attachments[attachment_idx]; + if (att_state->use_tlb_resolve) { + assert(att_state->has_resolve); const uint32_t resolve_attachment_idx = subpass->resolve_attachments[i].attachment; cmd_buffer_render_pass_emit_store(cmd_buffer, cl, @@ -609,7 +619,7 @@ cmd_buffer_render_pass_emit_stores(struct v3dv_cmd_buffer *cmd_buffer, RENDER_TARGET_0 + i, false, true); has_stores = true; - } else if (needs_resolve) { + } else if (att_state->has_resolve) { needs_store = true; }