From 3b5114a34b6fec78d7b719ed2c8d08152883e4b0 Mon Sep 17 00:00:00 2001 From: Rebecca Mckeever Date: Fri, 6 Dec 2024 17:50:27 -0800 Subject: [PATCH] vk/meta: Extend copy/fill/update helpers to support YCbCr Since copies happen one plane at a time, we can handle multiplanar copies like color copies. The user gets to decide the format to use for each plane, but the pipeline type and the optimal tile size applies to the whole image. Signed-off-by: Rebecca Mckeever Reviewed-by: Boris Brezillon Part-of: --- src/vulkan/runtime/vk_meta.h | 5 + src/vulkan/runtime/vk_meta_copy_fill_update.c | 155 ++++++++++++++++-- 2 files changed, 149 insertions(+), 11 deletions(-) diff --git a/src/vulkan/runtime/vk_meta.h b/src/vulkan/runtime/vk_meta.h index 60cf4cf2205..8d7ad182b7d 100644 --- a/src/vulkan/runtime/vk_meta.h +++ b/src/vulkan/runtime/vk_meta.h @@ -58,6 +58,11 @@ struct vk_meta_copy_image_properties { VkFormat view_format; } color; + struct { + /* Format to use for a specific image plane. */ + VkFormat view_format; + } plane[3]; + struct { struct { /* Format to use for the image view of a depth aspect. diff --git a/src/vulkan/runtime/vk_meta_copy_fill_update.c b/src/vulkan/runtime/vk_meta_copy_fill_update.c index 7dd1cf057fa..1ee59636d2f 100644 --- a/src/vulkan/runtime/vk_meta_copy_fill_update.c +++ b/src/vulkan/runtime/vk_meta_copy_fill_update.c @@ -53,6 +53,9 @@ struct vk_meta_copy_image_view { struct { VkFormat format; } color; + struct { + VkFormat format; + } plane; struct { struct { VkFormat format; @@ -278,6 +281,11 @@ copy_img_view_format_for_aspect(const struct vk_meta_copy_image_view *info, case VK_IMAGE_ASPECT_COLOR_BIT: return info->color.format; + case VK_IMAGE_ASPECT_PLANE_0_BIT: + case VK_IMAGE_ASPECT_PLANE_1_BIT: + case VK_IMAGE_ASPECT_PLANE_2_BIT: + return info->plane.format; + case VK_IMAGE_ASPECT_DEPTH_BIT: return info->depth.format; @@ -345,7 +353,13 @@ get_gfx_copy_pipeline( .layout = layout, }; - if (aspects & VK_IMAGE_ASPECT_COLOR_BIT) { + /* Since copies happen one plane at a time, multiplanar copies can be + * handled like color copies. + */ + if (aspects & + (VK_IMAGE_ASPECT_COLOR_BIT | + VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | + VK_IMAGE_ASPECT_PLANE_2_BIT)) { VkFormat fmt = copy_img_view_format_for_aspect(view, aspects); @@ -441,6 +455,13 @@ copy_create_src_image_view(struct vk_command_buffer *cmd, VkFormat format = copy_img_view_format_for_aspect(view_info, aspect); + /* For multiplane, we only want the aspect for the plane rather than the + * set of aspects for the full image. + */ + VkImageAspectFlags view_aspects = + aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) ? + vk_format_aspects(format) : aspect; + VkImageViewCreateInfo info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = &usage, @@ -449,7 +470,7 @@ copy_create_src_image_view(struct vk_command_buffer *cmd, .viewType = view_info->type, .format = format, .subresourceRange = { - .aspectMask = vk_format_aspects(format), + .aspectMask = view_aspects, .baseMipLevel = subres->mipLevel, .levelCount = 1, .baseArrayLayer = 0, @@ -488,7 +509,13 @@ copy_create_dst_image_view(struct vk_command_buffer *cmd, { uint32_t layer_count, base_layer; VkFormat format = copy_img_view_format_for_aspect(view_info, aspect); - VkImageAspectFlags fmt_aspects = vk_format_aspects(format); + + /* For multiplane, we only want the aspect for the plane rather than the + * set of aspects for the full image. + */ + VkImageAspectFlags view_aspects = + aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) ? + vk_format_aspects(format) : aspect; const VkImageViewUsageCreateInfo usage = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, .usage = bind_point == VK_PIPELINE_BIND_POINT_COMPUTE @@ -517,7 +544,7 @@ copy_create_dst_image_view(struct vk_command_buffer *cmd, : vk_image_storage_view_type(img), .format = format, .subresourceRange = { - .aspectMask = fmt_aspects, + .aspectMask = view_aspects, .baseMipLevel = subres->mipLevel, .levelCount = 1, .baseArrayLayer = base_layer, @@ -689,6 +716,9 @@ tex_deref(nir_builder *b, const struct vk_meta_copy_image_view *view, const char *tex_name; switch (aspect) { case VK_IMAGE_ASPECT_COLOR_BIT: + case VK_IMAGE_ASPECT_PLANE_0_BIT: + case VK_IMAGE_ASPECT_PLANE_1_BIT: + case VK_IMAGE_ASPECT_PLANE_2_BIT: tex_name = "color_tex"; break; case VK_IMAGE_ASPECT_DEPTH_BIT: @@ -731,6 +761,9 @@ img_deref(nir_builder *b, const struct vk_meta_copy_image_view *view, const char *img_name; switch (aspect) { case VK_IMAGE_ASPECT_COLOR_BIT: + case VK_IMAGE_ASPECT_PLANE_0_BIT: + case VK_IMAGE_ASPECT_PLANE_1_BIT: + case VK_IMAGE_ASPECT_PLANE_2_BIT: img_name = "color_img"; break; case VK_IMAGE_ASPECT_DEPTH_BIT: @@ -1277,9 +1310,10 @@ img_copy_view_info(VkImageViewType view_type, VkImageAspectFlags aspects, .type = view_type, }; - /* We only support color/depth/stencil aspects. */ - assert(aspects & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | - VK_IMAGE_ASPECT_STENCIL_BIT)); + assert(aspects & + (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | + VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)); if (aspects & VK_IMAGE_ASPECT_COLOR_BIT) { /* Color aspect can't be combined with other aspects. */ @@ -1289,6 +1323,26 @@ img_copy_view_info(VkImageViewType view_type, VkImageAspectFlags aspects, return view; } + if (aspects & + (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | + VK_IMAGE_ASPECT_PLANE_2_BIT)) { + switch (aspects) { + case VK_IMAGE_ASPECT_PLANE_0_BIT: + view.plane.format = img_props->plane[0].view_format; + break; + case VK_IMAGE_ASPECT_PLANE_1_BIT: + view.plane.format = img_props->plane[1].view_format; + break; + case VK_IMAGE_ASPECT_PLANE_2_BIT: + view.plane.format = img_props->plane[2].view_format; + break; + default: + unreachable("invalid ycbcr aspect"); + } + + assert(format_is_supported(view.color.format)); + return view; + } view.depth.format = img_props->depth.view_format; view.depth.component_mask = img_props->depth.component_mask; @@ -1878,6 +1932,10 @@ copy_image_prepare_compute_desc_set( if (unlikely(result != VK_SUCCESS)) return result; + if (region->srcSubresource.aspectMask != + region->dstSubresource.aspectMask) + aspect = region->dstSubresource.aspectMask; + result = copy_create_dst_image_view( cmd, meta, dst_img, &key->dst.view, aspect, ®ion->dstOffset, ®ion->extent, ®ion->dstSubresource, @@ -1995,6 +2053,83 @@ copy_image_prepare_gfx_push_const(struct vk_command_buffer *cmd, return VK_SUCCESS; } +static bool +valid_multiplane_aspect_mask(VkImageAspectFlags aspect) +{ + switch (aspect) { + case VK_IMAGE_ASPECT_PLANE_0_BIT: + case VK_IMAGE_ASPECT_PLANE_1_BIT: + case VK_IMAGE_ASPECT_PLANE_2_BIT: + return true; + default: + return false; + } +} + +static bool +aspect_masks_valid(struct vk_image *src_img, struct vk_image *dst_img, + const VkImageCopy2 *region) +{ + const struct vk_format_ycbcr_info *src_ycbcr_info = + vk_format_get_ycbcr_info(src_img->format); + const struct vk_format_ycbcr_info *dst_ycbcr_info = + vk_format_get_ycbcr_info(dst_img->format); + + /* From the Vulkan 1.4.303 spec, vkCmdCopyImage: + * + * VUID-vkCmdCopyImage-srcImage-01551 + * + * "If neither srcImage nor dstImage has a multi-planar image format + * then for each element of pRegions, srcSubresource.aspectMask and + * dstSubresource.aspectMask must match" + */ + if (!src_ycbcr_info && !dst_ycbcr_info) + return region->srcSubresource.aspectMask == + region->dstSubresource.aspectMask; + + /* VUID-vkCmdCopyImage-srcImage-08713 + * + * "If srcImage has a multi-planar image format, then for each element + * of pRegions, srcSubresource.aspectMask must be a single valid + * multi-planar aspect mask bit" + */ + if (src_ycbcr_info && + !valid_multiplane_aspect_mask(region->srcSubresource.aspectMask)) + return false; + + /* VUID-vkCmdCopyImage-dstImage-08714 + * + * "If dstImage has a multi-planar image format, then for each element + * of pRegions, dstSubresource.aspectMask must be a single valid + * multi-planar aspect mask bit" + */ + if (dst_ycbcr_info && + !valid_multiplane_aspect_mask(region->dstSubresource.aspectMask)) + return false; + + /* VUID-vkCmdCopyImage-srcImage-01556 + * + * "If srcImage has a multi-planar image format and the dstImage does + * not have a multi-planar image format, then for each element of + * pRegions, dstSubresource.aspectMask must be VK_IMAGE_ASPECT_COLOR_BIT" + */ + if (src_ycbcr_info && !dst_ycbcr_info && + region->dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) + return false; + + /* VUID-vkCmdCopyImage-dstImage-01557 + * + * "If dstImage has a multi-planar image format and the srcImage does + * not have a multi-planar image format, then for each element of + * pRegions, srcSubresource.aspectMask must be VK_IMAGE_ASPECT_COLOR_BIT" + */ + if (!src_ycbcr_info && dst_ycbcr_info && + region->srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) + return false; + + return true; +} + static void copy_image_region_gfx(struct vk_command_buffer *cmd, struct vk_meta_device *meta, struct vk_image *src_img, @@ -2016,8 +2151,7 @@ copy_image_region_gfx(struct vk_command_buffer *cmd, ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : (VkImageViewType)-1; - assert(region->srcSubresource.aspectMask == - region->dstSubresource.aspectMask); + assert(aspect_masks_valid(src_img, dst_img, region)); struct vk_meta_copy_image_key key = { .key_type = VK_META_OBJECT_KEY_COPY_IMAGE_GFX, @@ -2076,8 +2210,7 @@ copy_image_region_compute(struct vk_command_buffer *cmd, const struct vk_device_dispatch_table *disp = &dev->dispatch_table; VkImageViewType dst_view_type = vk_image_storage_view_type(dst_img); - assert(region->srcSubresource.aspectMask == - region->dstSubresource.aspectMask); + assert(aspect_masks_valid(src_img, dst_img, region)); struct vk_meta_copy_image_key key = { .key_type = VK_META_OBJECT_KEY_COPY_IMAGE_CS,