mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-22 17:50:12 +01:00
anv: Stop resolving CCS implicitly
With an earlier patch from this series, resolves are additionally performed on layout transitions. Remove the now unnecessary implicit resolves within render passes. Signed-off-by: Nanley Chery <nanley.g.chery@intel.com> Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
This commit is contained in:
parent
5ba93e6f5a
commit
597ff919e7
3 changed files with 5 additions and 169 deletions
|
|
@ -1502,150 +1502,16 @@ anv_image_fast_clear(struct anv_cmd_buffer *cmd_buffer,
|
||||||
ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT | ANV_PIPE_CS_STALL_BIT;
|
ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT | ANV_PIPE_CS_STALL_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
ccs_resolve_attachment(struct anv_cmd_buffer *cmd_buffer,
|
|
||||||
uint32_t att)
|
|
||||||
{
|
|
||||||
struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
|
|
||||||
struct anv_attachment_state *att_state =
|
|
||||||
&cmd_buffer->state.attachments[att];
|
|
||||||
|
|
||||||
if (att_state->aux_usage == ISL_AUX_USAGE_NONE ||
|
|
||||||
att_state->aux_usage == ISL_AUX_USAGE_MCS)
|
|
||||||
return; /* Nothing to resolve */
|
|
||||||
|
|
||||||
assert(att_state->aux_usage == ISL_AUX_USAGE_CCS_E ||
|
|
||||||
att_state->aux_usage == ISL_AUX_USAGE_CCS_D);
|
|
||||||
|
|
||||||
struct anv_render_pass *pass = cmd_buffer->state.pass;
|
|
||||||
const uint32_t subpass_idx = anv_get_subpass_id(&cmd_buffer->state);
|
|
||||||
|
|
||||||
/* Scan forward to see what all ways this attachment will be used.
|
|
||||||
* Ideally, we would like to resolve in the same subpass as the last write
|
|
||||||
* of a particular attachment. That way we only resolve once but it's
|
|
||||||
* still hot in the cache.
|
|
||||||
*/
|
|
||||||
bool found_draw = false;
|
|
||||||
enum anv_subpass_usage usage = 0;
|
|
||||||
for (uint32_t s = subpass_idx + 1; s < pass->subpass_count; s++) {
|
|
||||||
usage |= pass->attachments[att].subpass_usage[s];
|
|
||||||
|
|
||||||
if (usage & (ANV_SUBPASS_USAGE_DRAW | ANV_SUBPASS_USAGE_RESOLVE_DST)) {
|
|
||||||
/* We found another subpass that draws to this attachment. We'll
|
|
||||||
* wait to resolve until then.
|
|
||||||
*/
|
|
||||||
found_draw = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct anv_image_view *iview = fb->attachments[att];
|
|
||||||
const struct anv_image *image = iview->image;
|
|
||||||
assert(image->aspects == VK_IMAGE_ASPECT_COLOR_BIT);
|
|
||||||
|
|
||||||
enum blorp_fast_clear_op resolve_op = BLORP_FAST_CLEAR_OP_NONE;
|
|
||||||
if (!found_draw) {
|
|
||||||
/* This is the last subpass that writes to this attachment so we need to
|
|
||||||
* resolve here. Ideally, we would like to only resolve if the storeOp
|
|
||||||
* is set to VK_ATTACHMENT_STORE_OP_STORE. However, we need to ensure
|
|
||||||
* that the CCS bits are set to "resolved" because there may be copy or
|
|
||||||
* blit operations (which may ignore CCS) between now and the next time
|
|
||||||
* we render and we need to ensure that anything they write will be
|
|
||||||
* respected in the next render. Unfortunately, the hardware does not
|
|
||||||
* provide us with any sort of "invalidate" pass that sets the CCS to
|
|
||||||
* "resolved" without writing to the render target.
|
|
||||||
*/
|
|
||||||
if (iview->image->aux_usage != ISL_AUX_USAGE_CCS_E) {
|
|
||||||
/* The image destination surface doesn't support compression outside
|
|
||||||
* the render pass. We need a full resolve.
|
|
||||||
*/
|
|
||||||
resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
|
|
||||||
} else if (att_state->fast_clear) {
|
|
||||||
/* We don't know what to do with clear colors outside the render
|
|
||||||
* pass. We need a partial resolve. Only transparent black is
|
|
||||||
* built into the surface state object and thus no resolve is
|
|
||||||
* required for this case.
|
|
||||||
*/
|
|
||||||
if (att_state->clear_value.color.uint32[0] ||
|
|
||||||
att_state->clear_value.color.uint32[1] ||
|
|
||||||
att_state->clear_value.color.uint32[2] ||
|
|
||||||
att_state->clear_value.color.uint32[3])
|
|
||||||
resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL;
|
|
||||||
} else {
|
|
||||||
/* The image "natively" supports all the compression we care about
|
|
||||||
* and we don't need to resolve at all. If this is the case, we also
|
|
||||||
* don't need to resolve for any of the input attachment cases below.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
} else if (usage & ANV_SUBPASS_USAGE_INPUT) {
|
|
||||||
/* Input attachments are clear-color aware so, at least on Sky Lake, we
|
|
||||||
* can frequently sample from them with no resolves at all.
|
|
||||||
*/
|
|
||||||
if (att_state->aux_usage != att_state->input_aux_usage) {
|
|
||||||
assert(att_state->input_aux_usage == ISL_AUX_USAGE_NONE);
|
|
||||||
resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
|
|
||||||
} else if (!att_state->clear_color_is_zero_one) {
|
|
||||||
/* Sky Lake PRM, Vol. 2d, RENDER_SURFACE_STATE::Red Clear Color:
|
|
||||||
*
|
|
||||||
* "If Number of Multisamples is MULTISAMPLECOUNT_1 AND if this RT
|
|
||||||
* is fast cleared with non-0/1 clear value, this RT must be
|
|
||||||
* partially resolved (refer to Partial Resolve operation) before
|
|
||||||
* binding this surface to Sampler."
|
|
||||||
*/
|
|
||||||
resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolve_op == BLORP_FAST_CLEAR_OP_NONE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* From the Sky Lake PRM Vol. 7, "Render Target Resolve":
|
|
||||||
*
|
|
||||||
* "When performing a render target resolve, PIPE_CONTROL with end of
|
|
||||||
* pipe sync must be delivered."
|
|
||||||
*
|
|
||||||
* This comment is a bit cryptic and doesn't really tell you what's going
|
|
||||||
* or what's really needed. It appears that fast clear ops are not
|
|
||||||
* properly synchronized with other drawing. We need to use a PIPE_CONTROL
|
|
||||||
* to ensure that the contents of the previous draw hit the render target
|
|
||||||
* before we resolve and then use a second PIPE_CONTROL after the resolve
|
|
||||||
* to ensure that it is completed before any additional drawing occurs.
|
|
||||||
*/
|
|
||||||
cmd_buffer->state.pending_pipe_bits |=
|
|
||||||
ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT | ANV_PIPE_CS_STALL_BIT;
|
|
||||||
|
|
||||||
const uint32_t aux_layers =
|
|
||||||
anv_image_aux_layers(image, iview->isl.base_level);
|
|
||||||
anv_ccs_resolve(cmd_buffer, att_state->color_rt_state, image,
|
|
||||||
iview->isl.base_level, MIN2(fb->layers, aux_layers),
|
|
||||||
resolve_op);
|
|
||||||
|
|
||||||
cmd_buffer->state.pending_pipe_bits |=
|
|
||||||
ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT | ANV_PIPE_CS_STALL_BIT;
|
|
||||||
|
|
||||||
/* Once we've done any sort of resolve, we're no longer fast-cleared */
|
|
||||||
att_state->fast_clear = false;
|
|
||||||
if (att_state->aux_usage == ISL_AUX_USAGE_CCS_D)
|
|
||||||
att_state->aux_usage = ISL_AUX_USAGE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
anv_cmd_buffer_resolve_subpass(struct anv_cmd_buffer *cmd_buffer)
|
anv_cmd_buffer_resolve_subpass(struct anv_cmd_buffer *cmd_buffer)
|
||||||
{
|
{
|
||||||
struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
|
struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
|
||||||
struct anv_subpass *subpass = cmd_buffer->state.subpass;
|
struct anv_subpass *subpass = cmd_buffer->state.subpass;
|
||||||
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < subpass->color_count; ++i) {
|
|
||||||
const uint32_t att = subpass->color_attachments[i].attachment;
|
|
||||||
if (att == VK_ATTACHMENT_UNUSED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
assert(att < cmd_buffer->state.pass->attachment_count);
|
|
||||||
ccs_resolve_attachment(cmd_buffer, att);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subpass->has_resolve) {
|
if (subpass->has_resolve) {
|
||||||
|
struct blorp_batch batch;
|
||||||
|
blorp_batch_init(&cmd_buffer->device->blorp, &batch, cmd_buffer, 0);
|
||||||
|
|
||||||
/* We are about to do some MSAA resolves. We need to flush so that the
|
/* We are about to do some MSAA resolves. We need to flush so that the
|
||||||
* result of writes to the MSAA color attachments show up in the sampler
|
* result of writes to the MSAA color attachments show up in the sampler
|
||||||
* when we blit to the single-sampled resolve target.
|
* when we blit to the single-sampled resolve target.
|
||||||
|
|
@ -1687,9 +1553,6 @@ anv_cmd_buffer_resolve_subpass(struct anv_cmd_buffer *cmd_buffer)
|
||||||
|
|
||||||
assert(src_iview->aspect_mask == dst_iview->aspect_mask);
|
assert(src_iview->aspect_mask == dst_iview->aspect_mask);
|
||||||
|
|
||||||
struct blorp_batch batch;
|
|
||||||
blorp_batch_init(&cmd_buffer->device->blorp, &batch, cmd_buffer, 0);
|
|
||||||
|
|
||||||
resolve_image(&batch, src_iview->image, src_aux_usage,
|
resolve_image(&batch, src_iview->image, src_aux_usage,
|
||||||
src_iview->isl.base_level,
|
src_iview->isl.base_level,
|
||||||
src_iview->isl.base_array_layer,
|
src_iview->isl.base_array_layer,
|
||||||
|
|
@ -1700,15 +1563,12 @@ anv_cmd_buffer_resolve_subpass(struct anv_cmd_buffer *cmd_buffer)
|
||||||
render_area.offset.x, render_area.offset.y,
|
render_area.offset.x, render_area.offset.y,
|
||||||
render_area.offset.x, render_area.offset.y,
|
render_area.offset.x, render_area.offset.y,
|
||||||
render_area.extent.width, render_area.extent.height);
|
render_area.extent.width, render_area.extent.height);
|
||||||
|
}
|
||||||
|
|
||||||
blorp_batch_finish(&batch);
|
blorp_batch_finish(&batch);
|
||||||
|
|
||||||
ccs_resolve_attachment(cmd_buffer, dst_att);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
anv_gen8_hiz_op_resolve(struct anv_cmd_buffer *cmd_buffer,
|
anv_gen8_hiz_op_resolve(struct anv_cmd_buffer *cmd_buffer,
|
||||||
const struct anv_image *image,
|
const struct anv_image *image,
|
||||||
|
|
|
||||||
|
|
@ -73,10 +73,6 @@ VkResult anv_CreateRenderPass(
|
||||||
}
|
}
|
||||||
anv_multialloc_add(&ma, &subpass_attachments, subpass_attachment_count);
|
anv_multialloc_add(&ma, &subpass_attachments, subpass_attachment_count);
|
||||||
|
|
||||||
enum anv_subpass_usage *subpass_usages;
|
|
||||||
anv_multialloc_add(&ma, &subpass_usages,
|
|
||||||
pCreateInfo->subpassCount * pCreateInfo->attachmentCount);
|
|
||||||
|
|
||||||
if (!anv_multialloc_alloc2(&ma, &device->alloc, pAllocator,
|
if (!anv_multialloc_alloc2(&ma, &device->alloc, pAllocator,
|
||||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
|
||||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||||
|
|
@ -102,8 +98,6 @@ VkResult anv_CreateRenderPass(
|
||||||
att->initial_layout = pCreateInfo->pAttachments[i].initialLayout;
|
att->initial_layout = pCreateInfo->pAttachments[i].initialLayout;
|
||||||
att->final_layout = pCreateInfo->pAttachments[i].finalLayout;
|
att->final_layout = pCreateInfo->pAttachments[i].finalLayout;
|
||||||
att->first_subpass_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
att->first_subpass_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
att->subpass_usage = subpass_usages;
|
|
||||||
subpass_usages += pass->subpass_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_color = false, has_depth = false, has_input = false;
|
bool has_color = false, has_depth = false, has_input = false;
|
||||||
|
|
@ -127,7 +121,6 @@ VkResult anv_CreateRenderPass(
|
||||||
if (a != VK_ATTACHMENT_UNUSED) {
|
if (a != VK_ATTACHMENT_UNUSED) {
|
||||||
has_input = true;
|
has_input = true;
|
||||||
pass->attachments[a].usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
pass->attachments[a].usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||||
pass->attachments[a].subpass_usage[i] |= ANV_SUBPASS_USAGE_INPUT;
|
|
||||||
pass->attachments[a].last_subpass_idx = i;
|
pass->attachments[a].last_subpass_idx = i;
|
||||||
|
|
||||||
init_first_subpass_layout(&pass->attachments[a],
|
init_first_subpass_layout(&pass->attachments[a],
|
||||||
|
|
@ -149,7 +142,6 @@ VkResult anv_CreateRenderPass(
|
||||||
if (a != VK_ATTACHMENT_UNUSED) {
|
if (a != VK_ATTACHMENT_UNUSED) {
|
||||||
has_color = true;
|
has_color = true;
|
||||||
pass->attachments[a].usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
pass->attachments[a].usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
pass->attachments[a].subpass_usage[i] |= ANV_SUBPASS_USAGE_DRAW;
|
|
||||||
pass->attachments[a].last_subpass_idx = i;
|
pass->attachments[a].last_subpass_idx = i;
|
||||||
|
|
||||||
init_first_subpass_layout(&pass->attachments[a],
|
init_first_subpass_layout(&pass->attachments[a],
|
||||||
|
|
@ -172,11 +164,6 @@ VkResult anv_CreateRenderPass(
|
||||||
pass->attachments[color_att].usage |=
|
pass->attachments[color_att].usage |=
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
pass->attachments[a].usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
pass->attachments[a].usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
pass->attachments[color_att].subpass_usage[i] |=
|
|
||||||
ANV_SUBPASS_USAGE_RESOLVE_SRC;
|
|
||||||
pass->attachments[a].subpass_usage[i] |=
|
|
||||||
ANV_SUBPASS_USAGE_RESOLVE_DST;
|
|
||||||
pass->attachments[a].last_subpass_idx = i;
|
pass->attachments[a].last_subpass_idx = i;
|
||||||
|
|
||||||
init_first_subpass_layout(&pass->attachments[a],
|
init_first_subpass_layout(&pass->attachments[a],
|
||||||
|
|
@ -193,7 +180,6 @@ VkResult anv_CreateRenderPass(
|
||||||
has_depth = true;
|
has_depth = true;
|
||||||
pass->attachments[a].usage |=
|
pass->attachments[a].usage |=
|
||||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
pass->attachments[a].subpass_usage[i] |= ANV_SUBPASS_USAGE_DRAW;
|
|
||||||
pass->attachments[a].last_subpass_idx = i;
|
pass->attachments[a].last_subpass_idx = i;
|
||||||
|
|
||||||
init_first_subpass_layout(&pass->attachments[a],
|
init_first_subpass_layout(&pass->attachments[a],
|
||||||
|
|
|
||||||
|
|
@ -2290,13 +2290,6 @@ anv_subpass_view_count(const struct anv_subpass *subpass)
|
||||||
return MAX2(1, _mesa_bitcount(subpass->view_mask));
|
return MAX2(1, _mesa_bitcount(subpass->view_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum anv_subpass_usage {
|
|
||||||
ANV_SUBPASS_USAGE_DRAW = (1 << 0),
|
|
||||||
ANV_SUBPASS_USAGE_INPUT = (1 << 1),
|
|
||||||
ANV_SUBPASS_USAGE_RESOLVE_SRC = (1 << 2),
|
|
||||||
ANV_SUBPASS_USAGE_RESOLVE_DST = (1 << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct anv_render_pass_attachment {
|
struct anv_render_pass_attachment {
|
||||||
/* TODO: Consider using VkAttachmentDescription instead of storing each of
|
/* TODO: Consider using VkAttachmentDescription instead of storing each of
|
||||||
* its members individually.
|
* its members individually.
|
||||||
|
|
@ -2311,9 +2304,6 @@ struct anv_render_pass_attachment {
|
||||||
VkImageLayout final_layout;
|
VkImageLayout final_layout;
|
||||||
VkImageLayout first_subpass_layout;
|
VkImageLayout first_subpass_layout;
|
||||||
|
|
||||||
/* An array, indexed by subpass id, of how the attachment will be used. */
|
|
||||||
enum anv_subpass_usage * subpass_usage;
|
|
||||||
|
|
||||||
/* The subpass id in which the attachment will be used last. */
|
/* The subpass id in which the attachment will be used last. */
|
||||||
uint32_t last_subpass_idx;
|
uint32_t last_subpass_idx;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue