From 174591a73a7353fddfc666c62d3dcd7d9def6d8d Mon Sep 17 00:00:00 2001 From: Jakob Sinclair Date: Thu, 30 Apr 2026 11:04:23 +0200 Subject: [PATCH] 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. --- src/panfrost/vulkan/csf/panvk_cmd_buffer.h | 5 + src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c | 212 +++++++++++++++++--- src/panfrost/vulkan/panvk_vX_cmd_meta.c | 5 + 3 files changed, 196 insertions(+), 26 deletions(-) diff --git a/src/panfrost/vulkan/csf/panvk_cmd_buffer.h b/src/panfrost/vulkan/csf/panvk_cmd_buffer.h index 8caf8afca37..327421fc61a 100644 --- a/src/panfrost/vulkan/csf/panvk_cmd_buffer.h +++ b/src/panfrost/vulkan/csf/panvk_cmd_buffer.h @@ -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 diff --git a/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c b/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c index 653e9c456dd..7804f759528 100644 --- a/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c +++ b/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c @@ -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); } diff --git a/src/panfrost/vulkan/panvk_vX_cmd_meta.c b/src/panfrost/vulkan/panvk_vX_cmd_meta.c index 7608408aee9..ff4443b1bfb 100644 --- a/src/panfrost/vulkan/panvk_vX_cmd_meta.c +++ b/src/panfrost/vulkan/panvk_vX_cmd_meta.c @@ -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); }