v3dv: fallback to blit resolve if render area is not aligned to tile boundaries

Just as with all other TLB operations, we can only use the TLB if the render
area is aligned to tile boundaries. If it is not, then the operation would
overwrite pixels outside the render area, which is not allowed.

In this case, we can't even emit a previous TLB load to fix this because the
TLB has the multisampled attachment, not the resolve attachment, which is
just a destination buffer for the tile store.

Because the condition for tile alignment has to be determined for each
subpass, we handle this by storing this information in the attachment
state of the command buffer with the start of each subpass. We store
whether the attachment is to be resolved and whether it can use the
TLB (considering tile alignment restrictions).

Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14752>
This commit is contained in:
Iago Toral Quiroga 2022-01-27 11:11:51 +01:00 committed by Marge Bot
parent 7f87a1256e
commit 668653f830
4 changed files with 88 additions and 21 deletions

View file

@ -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.

View file

@ -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++) {

View file

@ -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 {

View file

@ -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;
}