mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 22:38:05 +02:00
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:
parent
7f87a1256e
commit
668653f830
4 changed files with 88 additions and 21 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue