vulkan/render_pass: Add an optimization for UNDEFINED+LOAD_OP_CLEAR

Reviewed-by: Ivan Briano <ivan.briano@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14961>
This commit is contained in:
Jason Ekstrand
2022-02-17 12:58:39 -06:00
parent 17395d395a
commit c3d8ca9300
2 changed files with 192 additions and 0 deletions

View File

@@ -982,6 +982,110 @@ transition_image_range(const struct vk_image_view *image_view,
}
}
static bool
can_use_attachment_initial_layout(struct vk_command_buffer *cmd_buffer,
uint32_t att_idx,
uint32_t view_mask,
VkImageLayout *layout_out,
VkImageLayout *stencil_layout_out)
{
const struct vk_render_pass *pass = cmd_buffer->render_pass;
const struct vk_framebuffer *framebuffer = cmd_buffer->framebuffer;
const struct vk_render_pass_attachment *rp_att = &pass->attachments[att_idx];
struct vk_attachment_state *att_state = &cmd_buffer->attachments[att_idx];
const struct vk_image_view *image_view = att_state->image_view;
if ((rp_att->aspects & ~VK_IMAGE_ASPECT_STENCIL_BIT) &&
rp_att->load_op != VK_ATTACHMENT_LOAD_OP_CLEAR)
return false;
if ((rp_att->aspects & VK_IMAGE_ASPECT_STENCIL_BIT) &&
rp_att->stencil_load_op != VK_ATTACHMENT_LOAD_OP_CLEAR)
return false;
if (cmd_buffer->render_area.offset.x != 0 ||
cmd_buffer->render_area.offset.y != 0 ||
cmd_buffer->render_area.extent.width != image_view->extent.width ||
cmd_buffer->render_area.extent.height != image_view->extent.height)
return false;
if (image_view->image->image_type == VK_IMAGE_TYPE_3D) {
/* For 3D images, the view has to be the whole thing */
if (image_view->base_array_layer != 0)
return false;
if (pass->is_multiview) {
if (!util_is_power_of_two_or_zero(view_mask + 1) ||
util_last_bit(view_mask) != image_view->layer_count)
return false;
} else {
if (framebuffer->layers != image_view->layer_count)
return false;
}
}
/* Finally, check if the entire thing is undefined. It's ok to smash the
* view_mask now as the only thing using it will be the loop below.
*/
/* 3D is stupidly special. See transition_attachment() */
if (image_view->image->image_type == VK_IMAGE_TYPE_3D)
view_mask = 1;
VkImageLayout layout = VK_IMAGE_LAYOUT_MAX_ENUM;
VkImageLayout stencil_layout = VK_IMAGE_LAYOUT_MAX_ENUM;
assert(view_mask != 0);
u_foreach_bit(view, view_mask) {
assert(view >= 0 && view < MESA_VK_MAX_MULTIVIEW_VIEW_COUNT);
struct vk_attachment_view_state *att_view_state = &att_state->views[view];
if (rp_att->aspects & ~VK_IMAGE_ASPECT_STENCIL_BIT) {
if (layout == VK_IMAGE_LAYOUT_MAX_ENUM)
layout = att_view_state->layout;
else if (layout != att_view_state->layout)
return false;
}
if (rp_att->aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
if (stencil_layout == VK_IMAGE_LAYOUT_MAX_ENUM)
stencil_layout = att_view_state->stencil_layout;
else if (stencil_layout != att_view_state->stencil_layout)
return false;
}
}
if (layout != VK_IMAGE_LAYOUT_MAX_ENUM)
*layout_out = layout;
else if (layout_out != NULL)
*layout_out = VK_IMAGE_LAYOUT_UNDEFINED;
if (stencil_layout != VK_IMAGE_LAYOUT_MAX_ENUM)
*stencil_layout_out = stencil_layout;
else if (stencil_layout_out != NULL)
*stencil_layout_out = VK_IMAGE_LAYOUT_UNDEFINED;
return true;
}
static void
set_attachment_layout(struct vk_command_buffer *cmd_buffer,
uint32_t att_idx,
uint32_t view_mask,
VkImageLayout layout,
VkImageLayout stencil_layout)
{
struct vk_attachment_state *att_state = &cmd_buffer->attachments[att_idx];
u_foreach_bit(view, view_mask) {
assert(view >= 0 && view < MESA_VK_MAX_MULTIVIEW_VIEW_COUNT);
struct vk_attachment_view_state *att_view_state = &att_state->views[view];
att_view_state->layout = layout;
att_view_state->stencil_layout = stencil_layout;
}
}
static void
transition_attachment(struct vk_command_buffer *cmd_buffer,
uint32_t att_idx,
@@ -1170,6 +1274,9 @@ begin_subpass(struct vk_command_buffer *cmd_buffer,
STACK_ARRAY(VkRenderingAttachmentInfo, color_attachments,
subpass->color_count);
STACK_ARRAY(VkRenderingAttachmentInitialLayoutInfoMESA,
color_attachment_initial_layouts,
subpass->color_count);
for (uint32_t i = 0; i < subpass->color_count; i++) {
const struct vk_subpass_attachment *sp_att =
@@ -1201,6 +1308,27 @@ begin_subpass(struct vk_command_buffer *cmd_buffer,
color_attachment->loadOp = rp_att->load_op;
color_attachment->clearValue = att_state->clear_value;
att_state->views_loaded |= subpass->view_mask;
VkImageLayout initial_layout;
if (can_use_attachment_initial_layout(cmd_buffer,
sp_att->attachment,
subpass->view_mask,
&initial_layout, NULL) &&
sp_att->layout != initial_layout) {
assert(color_attachment->loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
VkRenderingAttachmentInitialLayoutInfoMESA *color_initial_layout =
&color_attachment_initial_layouts[i];
*color_initial_layout = (VkRenderingAttachmentInitialLayoutInfoMESA) {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INITIAL_LAYOUT_INFO_MESA,
.initialLayout = initial_layout,
};
__vk_append_struct(color_attachment, color_initial_layout);
set_attachment_layout(cmd_buffer, sp_att->attachment,
subpass->view_mask,
sp_att->layout, VK_IMAGE_LAYOUT_UNDEFINED);
}
} else {
/* We've seen at least one of the views of this attachment before so
* we need to LOAD_OP_LOAD.
@@ -1250,6 +1378,12 @@ begin_subpass(struct vk_command_buffer *cmd_buffer,
VkRenderingAttachmentInfo stencil_attachment = {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
};
VkRenderingAttachmentInitialLayoutInfoMESA depth_initial_layout = {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INITIAL_LAYOUT_INFO_MESA,
};
VkRenderingAttachmentInitialLayoutInfoMESA stencil_initial_layout = {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INITIAL_LAYOUT_INFO_MESA,
};
if (subpass->depth_stencil_attachment != NULL) {
const struct vk_subpass_attachment *sp_att =
@@ -1281,6 +1415,33 @@ begin_subpass(struct vk_command_buffer *cmd_buffer,
stencil_attachment.loadOp = rp_att->stencil_load_op;
stencil_attachment.clearValue = att_state->clear_value;
att_state->views_loaded |= subpass->view_mask;
VkImageLayout initial_layout, initial_stencil_layout;
if (can_use_attachment_initial_layout(cmd_buffer,
sp_att->attachment,
subpass->view_mask,
&initial_layout,
&initial_stencil_layout)) {
if ((rp_att->aspects & VK_IMAGE_ASPECT_DEPTH_BIT) &&
sp_att->layout != initial_layout) {
assert(depth_attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
depth_initial_layout.initialLayout = initial_layout;
__vk_append_struct(&depth_attachment,
&depth_initial_layout);
}
if ((rp_att->aspects & VK_IMAGE_ASPECT_STENCIL_BIT) &&
sp_att->stencil_layout != initial_stencil_layout) {
assert(stencil_attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
stencil_initial_layout.initialLayout = initial_stencil_layout;
__vk_append_struct(&stencil_attachment,
&stencil_initial_layout);
}
set_attachment_layout(cmd_buffer, sp_att->attachment,
subpass->view_mask,
sp_att->layout, sp_att->stencil_layout);
}
} else {
/* We've seen at least one of the views of this attachment before so
* we need to LOAD_OP_LOAD.
@@ -1533,6 +1694,7 @@ begin_subpass(struct vk_command_buffer *cmd_buffer,
&rendering);
STACK_ARRAY_FINISH(color_attachments);
STACK_ARRAY_FINISH(color_attachment_initial_layouts);
}
static void

View File

@@ -49,6 +49,36 @@ typedef struct VkRenderingSelfDependencyInfoMESA {
VkBool32 stencilSelfDependency;
} VkRenderingSelfDependencyInfoMESA;
/**
* Pseudo-extension struct that may be chained into VkRenderingAttachmentInfo
* to indicate an initial layout for the attachment. This is only allowed if
* all of the following conditions are met:
*
* 1. VkRenderingAttachmentInfo::loadOp == LOAD_OP_CLEAR
*
* 2. VkRenderingInfo::renderArea is tne entire image view LOD
*
* 3. For 3D image attachments, VkRenderingInfo::viewMask == 0 AND
* VkRenderingInfo::layerCount references the entire bound image view
* OR VkRenderingInfo::viewMask is dense (no holes) and references the
* entire bound image view. (2D and 2D array images have no such
* requirement.)
*
* If this struct is included in the pNext chain of a
* VkRenderingAttachmentInfo, the driver is responsible for transitioning the
* bound region of the image from
* VkRenderingAttachmentInitialLayoutInfoMESA::initialLayout to
* VkRenderingAttachmentInfo::imageLayout prior to rendering.
*/
typedef struct VkRenderingAttachmentInitialLayoutInfoMESA {
VkStructureType sType;
#define VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INITIAL_LAYOUT_INFO_MESA (VkStructureType)1000044901
const void* pNext;
/** Initial layout of the attachment */
VkImageLayout initialLayout;
} VkRenderingAttachmentInitialLayoutInfoMESA;
struct vk_subpass_attachment {
/** VkAttachmentReference2::attachment */
uint32_t attachment;