panvk/csf: Just issue RUN_FRAGMENT for cmdClearColorImage

The Vulkan meta path issues a full drawcall with a rectangle primitive
for cmdClearColorImage. We can instead just issue a RUN_FRAGMENT without
any primitives and setting a clear color. This will avoid executing a
shader at all in this case and just do a HW clear.
This commit is contained in:
Jakob Sinclair 2026-04-30 11:04:23 +02:00
parent ba35486229
commit 174591a73a
3 changed files with 196 additions and 26 deletions

View file

@ -540,6 +540,11 @@ panvk_cache_flush_is_nop(const struct panvk_cache_flush_info *cache_flush)
extern const struct vk_command_buffer_ops panvk_per_arch(cmd_buffer_ops);
void panvk_per_arch(cmd_fb_barrier)(struct panvk_cmd_buffer *cmdbuf);
void panvk_per_arch(cmd_clear_color_image)(
struct panvk_cmd_buffer *cmdbuf, struct panvk_device *dev,
struct panvk_image *image, VkImageLayout image_layout,
const VkClearColorValue *color_value, uint32_t range_count,
const VkImageSubresourceRange *ranges);
#if PAN_ARCH == 10
/* Match against all possible iter_sb values. The constant iter_sb value for

View file

@ -3648,6 +3648,190 @@ handle_deferred_queries(struct panvk_cmd_buffer *cmdbuf)
}
}
static struct panvk_image_view *
create_internal_panvk_image_view(struct vk_command_buffer *cmdbuf,
struct vk_meta_device *meta, VkImage image,
uint32_t level, uint32_t base_array_level,
uint32_t layer_count)
{
VK_FROM_HANDLE(panvk_image, pan_image, image);
VkImageViewUsageCreateInfo view_usage = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
};
if (pan_image->vk.aspects == VK_IMAGE_ASPECT_COLOR_BIT)
view_usage.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (pan_image->vk.aspects &
(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
view_usage.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
VkImageViewType view_type;
if (pan_image->vk.image_type == VK_IMAGE_TYPE_1D) {
view_type =
layer_count == 1 ? VK_IMAGE_VIEW_TYPE_1D : VK_IMAGE_VIEW_TYPE_1D_ARRAY;
} else {
assert((pan_image->vk.image_type == VK_IMAGE_TYPE_2D ||
pan_image->vk.image_type == VK_IMAGE_TYPE_3D) &&
"Invalid image type");
view_type =
layer_count == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
}
const VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.flags = VK_IMAGE_VIEW_CREATE_DRIVER_INTERNAL_BIT_MESA,
.pNext = &view_usage,
.image = image,
.viewType = view_type,
.format = pan_image->vk.format,
.subresourceRange = {
.aspectMask = pan_image->vk.aspects,
.baseMipLevel = level,
.levelCount = 1,
.baseArrayLayer = base_array_level,
.layerCount = layer_count,
}};
VkImageView image_view;
VkResult result =
vk_meta_create_image_view(cmdbuf, meta, &view_info, &image_view);
if (unlikely(result != VK_SUCCESS))
return NULL;
VK_FROM_HANDLE(panvk_image_view, pan_image_view, image_view);
return pan_image_view;
}
static void
setup_clear_render_state(struct panvk_cmd_buffer *cmdbuf,
struct panvk_image_view *clear_image_view,
VkImageLayout image_layout,
const VkClearValue clear_value, uint32_t layer_count)
{
const VkRenderingAttachmentInfo color_att = {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.imageView = panvk_image_view_to_handle(clear_image_view),
.imageLayout = image_layout,
.resolveMode = VK_RESOLVE_MODE_NONE,
.resolveImageView = VK_NULL_HANDLE,
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = clear_value,
};
const VkRenderingInfo info = {
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.flags = 0,
.renderArea =
{
.offset = {0, 0},
.extent =
{
.width = clear_image_view->vk.extent.width,
.height = clear_image_view->vk.extent.height,
},
},
.layerCount = layer_count,
.viewMask = 0,
.colorAttachmentCount = 1,
.pColorAttachments = &color_att,
.pDepthAttachment = NULL,
.pStencilAttachment = NULL,
};
panvk_per_arch(cmd_init_render_state)(cmdbuf, &info);
}
static void
reset_render_state(struct panvk_cmd_buffer *cmdbuf, bool suspending,
bool resolve_attachments)
{
memset(&cmdbuf->state.gfx.render.fbds, 0,
sizeof(cmdbuf->state.gfx.render.fbds));
memset(&cmdbuf->state.gfx.render.oq, 0, sizeof(cmdbuf->state.gfx.render.oq));
cmdbuf->state.gfx.render.tiler = 0;
/* If we're finished with this render pass, make sure we reset the flags
* so any barrier encountered after doesn't try to flush
* draws. */
cmdbuf->state.gfx.render.flags = 0;
cmdbuf->state.gfx.render.suspended = suspending;
if (resolve_attachments)
panvk_per_arch(cmd_meta_resolve_attachments)(cmdbuf);
struct panvk_device *dev = to_panvk_device(cmdbuf->vk.base.device);
struct panvk_instr_end_args instr_info = {
.render = {
.flags = cmdbuf->state.gfx.render.flags,
.fb = &cmdbuf->state.gfx.render.fb.layout,
}};
panvk_per_arch(panvk_instr_end_work_async)(
PANVK_SUBQUEUE_VERTEX_TILER, cmdbuf, PANVK_INSTR_WORK_TYPE_RENDER,
&instr_info, cs_defer(dev->csf.sb.all_iters_mask, 0));
panvk_per_arch(panvk_instr_end_work_async)(
PANVK_SUBQUEUE_FRAGMENT, cmdbuf, PANVK_INSTR_WORK_TYPE_RENDER,
&instr_info, cs_defer(dev->csf.sb.all_iters_mask, 0));
}
void
panvk_per_arch(cmd_clear_color_image)(struct panvk_cmd_buffer *cmdbuf,
struct panvk_device *dev,
struct panvk_image *image,
VkImageLayout image_layout,
const VkClearColorValue *color_value,
uint32_t range_count,
const VkImageSubresourceRange *ranges)
{
for (uint32_t r = 0; r < range_count; r++) {
const VkImageSubresourceRange *range = &ranges[r];
const uint32_t level_count =
vk_image_subresource_level_count(&image->vk, range);
for (uint32_t l = 0; l < level_count; l++) {
const uint32_t level = range->baseMipLevel + l;
uint32_t base_array_layer, layer_count;
if (image->vk.image_type == VK_IMAGE_TYPE_3D) {
const VkExtent3D level_extent =
vk_image_mip_level_extent(&image->vk, level);
base_array_layer = 0;
layer_count = level_extent.depth;
} else {
base_array_layer = range->baseArrayLayer;
layer_count = vk_image_subresource_layer_count(&image->vk, range);
}
VkImage p_image = panvk_image_to_handle(image);
struct panvk_image_view *image_view = create_internal_panvk_image_view(
&cmdbuf->vk, &dev->meta, p_image, level, base_array_layer,
layer_count);
if (unlikely(image_view == NULL)) {
reset_render_state(cmdbuf, false, false);
return;
}
const VkClearValue clear_value = {
.color = *color_value,
};
setup_clear_render_state(cmdbuf, image_view, image_layout, clear_value,
layer_count);
VkResult result = get_render_ctx(cmdbuf);
if (unlikely(result != VK_SUCCESS)) {
reset_render_state(cmdbuf, false, false);
return;
}
issue_fragment_jobs(cmdbuf);
reset_render_state(cmdbuf, false, false);
}
}
}
VKAPI_ATTR void VKAPI_CALL
panvk_per_arch(CmdEndRendering)(VkCommandBuffer commandBuffer)
{
@ -3697,31 +3881,7 @@ panvk_per_arch(CmdEndRendering)(VkCommandBuffer commandBuffer)
return;
}
memset(&cmdbuf->state.gfx.render.fbds, 0,
sizeof(cmdbuf->state.gfx.render.fbds));
memset(&cmdbuf->state.gfx.render.oq, 0, sizeof(cmdbuf->state.gfx.render.oq));
cmdbuf->state.gfx.render.tiler = 0;
/* If we're finished with this render pass, make sure we reset the flags
* so any barrier encountered after EndRendering() doesn't try to flush
* draws. */
cmdbuf->state.gfx.render.flags = 0;
cmdbuf->state.gfx.render.suspended = suspending;
/* If we're not suspending, we need to resolve attachments. */
if (!suspending)
panvk_per_arch(cmd_meta_resolve_attachments)(cmdbuf);
struct panvk_instr_end_args instr_info = {
.render = {
.flags = cmdbuf->state.gfx.render.flags,
.fb = &cmdbuf->state.gfx.render.fb.layout,
}};
struct panvk_device *dev = to_panvk_device(cmdbuf->vk.base.device);
panvk_per_arch(panvk_instr_end_work_async)(
PANVK_SUBQUEUE_VERTEX_TILER, cmdbuf, PANVK_INSTR_WORK_TYPE_RENDER,
&instr_info, cs_defer(dev->csf.sb.all_iters_mask, 0));
panvk_per_arch(panvk_instr_end_work_async)(
PANVK_SUBQUEUE_FRAGMENT, cmdbuf, PANVK_INSTR_WORK_TYPE_RENDER,
&instr_info, cs_defer(dev->csf.sb.all_iters_mask, 0));
bool resolve_attachments = !suspending;
reset_render_state(cmdbuf, suspending, resolve_attachments);
}

View file

@ -318,8 +318,13 @@ panvk_per_arch(CmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image,
struct panvk_cmd_meta_graphics_save_ctx save = {0};
meta_gfx_start(cmdbuf, &save);
#if PAN_ARCH >= 10
panvk_per_arch(cmd_clear_color_image)(cmdbuf, dev, img, imageLayout, pColor,
rangeCount, pRanges);
#else
vk_meta_clear_color_image(&cmdbuf->vk, &dev->meta, &img->vk, imageLayout,
img->vk.format, pColor, rangeCount, pRanges);
#endif
meta_gfx_end(cmdbuf, &save);
}