v3dv: remove fallback path for vkCmdClearAttachments
Now that we support layered clears this code is dead. Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11783>
This commit is contained in:
@@ -827,261 +827,6 @@ fail:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkFormat
|
|
||||||
get_color_format_for_depth_stencil_format(VkFormat format)
|
|
||||||
{
|
|
||||||
/* For single depth/stencil aspect formats, we just choose a compatible
|
|
||||||
* 1 channel format, but for combined depth/stencil we want an RGBA format
|
|
||||||
* so we can specify the channels we want to write.
|
|
||||||
*/
|
|
||||||
switch (format) {
|
|
||||||
case VK_FORMAT_D16_UNORM:
|
|
||||||
return VK_FORMAT_R16_UINT;
|
|
||||||
case VK_FORMAT_D32_SFLOAT:
|
|
||||||
return VK_FORMAT_R32_SFLOAT;
|
|
||||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
|
||||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
|
||||||
return VK_FORMAT_R8G8B8A8_UINT;
|
|
||||||
default:
|
|
||||||
unreachable("Unsupported depth/stencil format");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits a scissored quad in the clear color, however, unlike the subpass
|
|
||||||
* versions, this creates its own framebuffer setup with a single color
|
|
||||||
* attachment, and therefore spanws new jobs, making it much slower than the
|
|
||||||
* subpass version.
|
|
||||||
*
|
|
||||||
* This path is only used when we have clears on layers other than the
|
|
||||||
* base layer in a framebuffer attachment, since we don't currently
|
|
||||||
* support any form of layered rendering that would allow us to implement
|
|
||||||
* this in the subpass version.
|
|
||||||
*
|
|
||||||
* Notice this can also handle depth/stencil formats by rendering to the
|
|
||||||
* depth/stencil target using a compatible color format.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
emit_color_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
|
|
||||||
uint32_t attachment_idx,
|
|
||||||
VkFormat rt_format,
|
|
||||||
uint32_t rt_samples,
|
|
||||||
uint32_t rt_components,
|
|
||||||
VkClearColorValue clear_color,
|
|
||||||
const VkClearRect *rect)
|
|
||||||
{
|
|
||||||
assert(cmd_buffer->state.pass);
|
|
||||||
struct v3dv_device *device = cmd_buffer->device;
|
|
||||||
struct v3dv_render_pass *pass = cmd_buffer->state.pass;
|
|
||||||
|
|
||||||
assert(attachment_idx != VK_ATTACHMENT_UNUSED &&
|
|
||||||
attachment_idx < pass->attachment_count);
|
|
||||||
|
|
||||||
struct v3dv_meta_color_clear_pipeline *pipeline = NULL;
|
|
||||||
VkResult result =
|
|
||||||
get_color_clear_pipeline(device,
|
|
||||||
NULL, 0, /* Not using current subpass */
|
|
||||||
0, attachment_idx,
|
|
||||||
rt_format, rt_samples, rt_components, false,
|
|
||||||
&pipeline);
|
|
||||||
if (result != VK_SUCCESS) {
|
|
||||||
if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
|
|
||||||
v3dv_flag_oom(cmd_buffer, NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert(pipeline && pipeline->pipeline && pipeline->pass);
|
|
||||||
|
|
||||||
/* Since we are not emitting the draw call in the current subpass we should
|
|
||||||
* be caching the clear pipeline and we don't have to take care of destorying
|
|
||||||
* it below.
|
|
||||||
*/
|
|
||||||
assert(pipeline->cached);
|
|
||||||
|
|
||||||
/* Store command buffer state for the current subpass before we interrupt
|
|
||||||
* it to emit the color clear pass and then finish the job for the
|
|
||||||
* interrupted subpass.
|
|
||||||
*/
|
|
||||||
v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
|
|
||||||
v3dv_cmd_buffer_finish_job(cmd_buffer);
|
|
||||||
|
|
||||||
struct v3dv_framebuffer *subpass_fb =
|
|
||||||
v3dv_framebuffer_from_handle(cmd_buffer->state.meta.framebuffer);
|
|
||||||
VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
|
|
||||||
VkDevice device_handle = v3dv_device_to_handle(cmd_buffer->device);
|
|
||||||
|
|
||||||
/* If we are clearing a depth/stencil attachment as a color attachment
|
|
||||||
* then we need to configure the framebuffer to the compatible color
|
|
||||||
* format.
|
|
||||||
*/
|
|
||||||
const struct v3dv_image_view *att_iview =
|
|
||||||
subpass_fb->attachments[attachment_idx];
|
|
||||||
const bool is_depth_or_stencil =
|
|
||||||
vk_format_is_depth_or_stencil(att_iview->vk_format);
|
|
||||||
|
|
||||||
/* Emit the pass for each attachment layer, which creates a framebuffer
|
|
||||||
* for each selected layer of the attachment and then renders a scissored
|
|
||||||
* quad in the clear color.
|
|
||||||
*/
|
|
||||||
uint32_t dirty_dynamic_state = 0;
|
|
||||||
for (uint32_t i = 0; i < rect->layerCount; i++) {
|
|
||||||
VkImageViewCreateInfo fb_layer_view_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.image = v3dv_image_to_handle((struct v3dv_image *)att_iview->image),
|
|
||||||
.viewType =
|
|
||||||
v3dv_image_type_to_view_type(att_iview->image->type),
|
|
||||||
.format = is_depth_or_stencil ? rt_format : att_iview->vk_format,
|
|
||||||
.subresourceRange = {
|
|
||||||
.aspectMask = is_depth_or_stencil ? VK_IMAGE_ASPECT_COLOR_BIT :
|
|
||||||
att_iview->aspects,
|
|
||||||
.baseMipLevel = att_iview->base_level,
|
|
||||||
.levelCount = att_iview->max_level - att_iview->base_level + 1,
|
|
||||||
.baseArrayLayer = att_iview->first_layer + rect->baseArrayLayer + i,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
VkImageView fb_attachment;
|
|
||||||
result = v3dv_CreateImageView(v3dv_device_to_handle(device),
|
|
||||||
&fb_layer_view_info,
|
|
||||||
&device->vk.alloc, &fb_attachment);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
v3dv_cmd_buffer_add_private_obj(
|
|
||||||
cmd_buffer, (uintptr_t)fb_attachment,
|
|
||||||
(v3dv_cmd_buffer_private_obj_destroy_cb)v3dv_DestroyImageView);
|
|
||||||
|
|
||||||
VkFramebufferCreateInfo fb_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
||||||
.renderPass = v3dv_render_pass_to_handle(pass),
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = &fb_attachment,
|
|
||||||
.width = subpass_fb->width,
|
|
||||||
.height = subpass_fb->height,
|
|
||||||
.layers = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkFramebuffer fb;
|
|
||||||
result = v3dv_CreateFramebuffer(device_handle, &fb_info,
|
|
||||||
&cmd_buffer->device->vk.alloc, &fb);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
v3dv_cmd_buffer_add_private_obj(
|
|
||||||
cmd_buffer, (uintptr_t)fb,
|
|
||||||
(v3dv_cmd_buffer_private_obj_destroy_cb)v3dv_DestroyFramebuffer);
|
|
||||||
|
|
||||||
VkRenderPassBeginInfo rp_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
||||||
.renderPass = pipeline->pass,
|
|
||||||
.framebuffer = fb,
|
|
||||||
.renderArea = {
|
|
||||||
.offset = { rect->rect.offset.x, rect->rect.offset.y },
|
|
||||||
.extent = { rect->rect.extent.width, rect->rect.extent.height } },
|
|
||||||
.clearValueCount = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
v3dv_CmdBeginRenderPass(cmd_buffer_handle, &rp_info,
|
|
||||||
VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
|
|
||||||
struct v3dv_job *job = cmd_buffer->state.job;
|
|
||||||
if (!job)
|
|
||||||
goto fail;
|
|
||||||
job->is_subpass_continue = true;
|
|
||||||
|
|
||||||
v3dv_CmdPushConstants(cmd_buffer_handle,
|
|
||||||
device->meta.color_clear.p_layout,
|
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16,
|
|
||||||
&clear_color);
|
|
||||||
|
|
||||||
v3dv_CmdBindPipeline(cmd_buffer_handle,
|
|
||||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
||||||
pipeline->pipeline);
|
|
||||||
|
|
||||||
const VkViewport viewport = {
|
|
||||||
.x = rect->rect.offset.x,
|
|
||||||
.y = rect->rect.offset.y,
|
|
||||||
.width = rect->rect.extent.width,
|
|
||||||
.height = rect->rect.extent.height,
|
|
||||||
.minDepth = 0.0f,
|
|
||||||
.maxDepth = 1.0f
|
|
||||||
};
|
|
||||||
v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
|
|
||||||
v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rect->rect);
|
|
||||||
|
|
||||||
v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
|
|
||||||
|
|
||||||
v3dv_CmdEndRenderPass(cmd_buffer_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The clear pipeline sets viewport and scissor state, so we need
|
|
||||||
* to restore it
|
|
||||||
*/
|
|
||||||
dirty_dynamic_state = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dirty_dynamic_state, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
emit_ds_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
|
|
||||||
VkImageAspectFlags aspects,
|
|
||||||
uint32_t attachment_idx,
|
|
||||||
VkClearDepthStencilValue clear_ds,
|
|
||||||
const VkClearRect *rect)
|
|
||||||
{
|
|
||||||
assert(cmd_buffer->state.pass);
|
|
||||||
assert(attachment_idx != VK_ATTACHMENT_UNUSED);
|
|
||||||
assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
|
|
||||||
|
|
||||||
VkFormat format =
|
|
||||||
cmd_buffer->state.pass->attachments[attachment_idx].desc.format;
|
|
||||||
assert ((aspects & ~vk_format_aspects(format)) == 0);
|
|
||||||
|
|
||||||
uint32_t samples =
|
|
||||||
cmd_buffer->state.pass->attachments[attachment_idx].desc.samples;
|
|
||||||
|
|
||||||
enum pipe_format pformat = vk_format_to_pipe_format(format);
|
|
||||||
VkClearColorValue clear_color;
|
|
||||||
uint32_t clear_zs =
|
|
||||||
util_pack_z_stencil(pformat, clear_ds.depth, clear_ds.stencil);
|
|
||||||
|
|
||||||
/* We implement depth/stencil clears by turning them into color clears
|
|
||||||
* with a compatible color format.
|
|
||||||
*/
|
|
||||||
VkFormat color_format = get_color_format_for_depth_stencil_format(format);
|
|
||||||
|
|
||||||
uint32_t comps;
|
|
||||||
if (color_format == VK_FORMAT_R8G8B8A8_UINT) {
|
|
||||||
/* We are clearing a D24 format so we need to select the channels that we
|
|
||||||
* are being asked to clear to avoid clearing aspects that should be
|
|
||||||
* preserved. Also, the hardware uses the MSB channels to store the D24
|
|
||||||
* component, so we need to shift the components in the clear value to
|
|
||||||
* match that.
|
|
||||||
*/
|
|
||||||
comps = 0;
|
|
||||||
if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
|
|
||||||
comps |= VK_COLOR_COMPONENT_R_BIT;
|
|
||||||
clear_color.uint32[0] = clear_zs >> 24;
|
|
||||||
}
|
|
||||||
if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) {
|
|
||||||
comps |= VK_COLOR_COMPONENT_G_BIT |
|
|
||||||
VK_COLOR_COMPONENT_B_BIT |
|
|
||||||
VK_COLOR_COMPONENT_A_BIT;
|
|
||||||
clear_color.uint32[1] = (clear_zs >> 0) & 0xff;
|
|
||||||
clear_color.uint32[2] = (clear_zs >> 8) & 0xff;
|
|
||||||
clear_color.uint32[3] = (clear_zs >> 16) & 0xff;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* For anything else we use a single component format */
|
|
||||||
comps = VK_COLOR_COMPONENT_R_BIT;
|
|
||||||
clear_color.uint32[0] = clear_zs;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_color_clear_rect(cmd_buffer, attachment_idx,
|
|
||||||
color_format, samples, comps,
|
|
||||||
clear_color, rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Emits a scissored quad in the clear color */
|
/* Emits a scissored quad in the clear color */
|
||||||
static void
|
static void
|
||||||
emit_subpass_color_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
|
emit_subpass_color_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
|
||||||
@@ -1274,44 +1019,6 @@ emit_subpass_ds_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
|
|||||||
v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
|
v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
is_subrect(const VkRect2D *r0, const VkRect2D *r1)
|
|
||||||
{
|
|
||||||
return r0->offset.x <= r1->offset.x &&
|
|
||||||
r0->offset.y <= r1->offset.y &&
|
|
||||||
r0->offset.x + r0->extent.width >= r1->offset.x + r1->extent.width &&
|
|
||||||
r0->offset.y + r0->extent.height >= r1->offset.y + r1->extent.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
can_use_tlb_clear(struct v3dv_cmd_buffer *cmd_buffer,
|
|
||||||
uint32_t rect_count,
|
|
||||||
const VkClearRect* rects)
|
|
||||||
{
|
|
||||||
const struct v3dv_framebuffer *framebuffer = cmd_buffer->state.framebuffer;
|
|
||||||
|
|
||||||
const VkRect2D *render_area = &cmd_buffer->state.render_area;
|
|
||||||
|
|
||||||
/* Check if we are clearing a single region covering the entire framebuffer
|
|
||||||
* and that we are not constrained by the current render area.
|
|
||||||
*
|
|
||||||
* From the Vulkan 1.0 spec:
|
|
||||||
*
|
|
||||||
* "The vkCmdClearAttachments command is not affected by the bound
|
|
||||||
* pipeline state."
|
|
||||||
*
|
|
||||||
* So we can ignore scissor and viewport state for this check.
|
|
||||||
*/
|
|
||||||
const VkRect2D fb_rect = {
|
|
||||||
{ 0, 0 },
|
|
||||||
{ framebuffer->width, framebuffer->height }
|
|
||||||
};
|
|
||||||
|
|
||||||
return rect_count == 1 &&
|
|
||||||
is_subrect(&rects[0].rect, &fb_rect) &&
|
|
||||||
is_subrect(render_area, &fb_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_deferred_clear_attachments(struct v3dv_cmd_buffer *cmd_buffer,
|
handle_deferred_clear_attachments(struct v3dv_cmd_buffer *cmd_buffer,
|
||||||
uint32_t attachmentCount,
|
uint32_t attachmentCount,
|
||||||
@@ -1438,65 +1145,4 @@ v3dv_CmdClearAttachments(VkCommandBuffer commandBuffer,
|
|||||||
rectCount, pRects);
|
rectCount, pRects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
perf_debug("Falling back to slow path for vkCmdClearAttachments due to "
|
|
||||||
"clearing layers other than the base array layer.\n");
|
|
||||||
|
|
||||||
/* If we can't handle this as a draw call inside the current job then we
|
|
||||||
* will have to spawn jobs for the clears, which will be slow. In that case,
|
|
||||||
* try to use the TLB to clear if possible.
|
|
||||||
*/
|
|
||||||
if (can_use_tlb_clear(cmd_buffer, rectCount, pRects)) {
|
|
||||||
v3dv_X(cmd_buffer->device, cmd_buffer_emit_tlb_clear)
|
|
||||||
(cmd_buffer, attachmentCount, pAttachments,
|
|
||||||
pRects[0].baseArrayLayer, pRects[0].layerCount);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, fall back to drawing rects with the clear value using a
|
|
||||||
* separate job. This is the slowest path.
|
|
||||||
*/
|
|
||||||
for (uint32_t i = 0; i < attachmentCount; i++) {
|
|
||||||
uint32_t attachment_idx = VK_ATTACHMENT_UNUSED;
|
|
||||||
|
|
||||||
if (pAttachments[i].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
|
||||||
uint32_t rt_idx = pAttachments[i].colorAttachment;
|
|
||||||
attachment_idx = subpass->color_attachments[rt_idx].attachment;
|
|
||||||
} else if (pAttachments[i].aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT |
|
|
||||||
VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
|
||||||
attachment_idx = subpass->ds_attachment.attachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attachment_idx == VK_ATTACHMENT_UNUSED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pAttachments[i].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
|
||||||
const uint32_t components = VK_COLOR_COMPONENT_R_BIT |
|
|
||||||
VK_COLOR_COMPONENT_G_BIT |
|
|
||||||
VK_COLOR_COMPONENT_B_BIT |
|
|
||||||
VK_COLOR_COMPONENT_A_BIT;
|
|
||||||
const uint32_t samples =
|
|
||||||
cmd_buffer->state.pass->attachments[attachment_idx].desc.samples;
|
|
||||||
const VkFormat format =
|
|
||||||
cmd_buffer->state.pass->attachments[attachment_idx].desc.format;
|
|
||||||
for (uint32_t j = 0; j < rectCount; j++) {
|
|
||||||
emit_color_clear_rect(cmd_buffer,
|
|
||||||
attachment_idx,
|
|
||||||
format,
|
|
||||||
samples,
|
|
||||||
components,
|
|
||||||
pAttachments[i].clearValue.color,
|
|
||||||
&pRects[j]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (uint32_t j = 0; j < rectCount; j++) {
|
|
||||||
emit_ds_clear_rect(cmd_buffer,
|
|
||||||
pAttachments[i].aspectMask,
|
|
||||||
attachment_idx,
|
|
||||||
pAttachments[i].clearValue.depthStencil,
|
|
||||||
&pRects[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user