From 9cc004b3d0c0acb7057f408b9e954607fb18c69c Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 21 Jul 2021 22:02:14 -0500 Subject: [PATCH] vulkan: Add a vk_image_view struct Reviewed-by: Iago Toral Quiroga Part-of: --- src/vulkan/util/vk_image.c | 181 +++++++++++++++++++++++++++++++++++++ src/vulkan/util/vk_image.h | 96 ++++++++++++++++++++ 2 files changed, 277 insertions(+) diff --git a/src/vulkan/util/vk_image.c b/src/vulkan/util/vk_image.c index 89717739e2e..2e1f4add048 100644 --- a/src/vulkan/util/vk_image.c +++ b/src/vulkan/util/vk_image.c @@ -217,3 +217,184 @@ vk_image_expand_aspect_mask(const struct vk_image *image, return aspect_mask; } } + +static VkComponentSwizzle +remap_swizzle(VkComponentSwizzle swizzle, VkComponentSwizzle component) +{ + return swizzle == VK_COMPONENT_SWIZZLE_IDENTITY ? component : swizzle; +} + +void +vk_image_view_init(struct vk_device *device, + struct vk_image_view *image_view, + const VkImageViewCreateInfo *pCreateInfo) +{ + vk_object_base_init(device, &image_view->base, VK_OBJECT_TYPE_IMAGE_VIEW); + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); + VK_FROM_HANDLE(vk_image, image, pCreateInfo->image); + + image_view->create_flags = pCreateInfo->flags; + image_view->image = image; + image_view->view_type = pCreateInfo->viewType; + + switch (image_view->view_type) { + case VK_IMAGE_VIEW_TYPE_1D: + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: + assert(image->image_type == VK_IMAGE_TYPE_1D); + break; + case VK_IMAGE_VIEW_TYPE_2D: + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: + if (image->create_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) + assert(image->image_type == VK_IMAGE_TYPE_3D); + else + assert(image->image_type == VK_IMAGE_TYPE_2D); + break; + case VK_IMAGE_VIEW_TYPE_3D: + assert(image->image_type == VK_IMAGE_TYPE_3D); + break; + case VK_IMAGE_VIEW_TYPE_CUBE: + case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: + assert(image->image_type == VK_IMAGE_TYPE_2D); + assert(image->create_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); + break; + default: + unreachable("Invalid image view type"); + } + + const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange; + + image_view->aspects = vk_image_expand_aspect_mask(image, range->aspectMask); + + /* From the Vulkan 1.2.184 spec: + * + * "If the image has a multi-planar format and + * subresourceRange.aspectMask is VK_IMAGE_ASPECT_COLOR_BIT, and image + * has been created with a usage value not containing any of the + * VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR, and + * VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR flags, then the format must + * be identical to the image format, and the sampler to be used with the + * image view must enable sampler Y′CBCR conversion." + * + * Since no one implements video yet, we can ignore the bits about video + * create flags and assume YCbCr formats match. + */ + if ((image->aspects & VK_IMAGE_ASPECT_PLANE_1_BIT) && + (range->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)) + assert(pCreateInfo->format == image->format); + + /* From the Vulkan 1.2.184 spec: + * + * "Each depth/stencil format is only compatible with itself." + */ + if (image_view->aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT)) + assert(pCreateInfo->format == image->format); + + if (!(image->create_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) + assert(pCreateInfo->format == image->format); + + /* Restrict the format to only the planes chosen. + * + * For combined depth and stencil images, this means the depth-only or + * stencil-only format if only one aspect is chosen and the full combined + * format if both aspects are chosen. + * + * For single-plane color images, we just take the format as-is. For + * multi-plane views of multi-plane images, this means we want the full + * multi-plane format. For single-plane views of multi-plane images, we + * want a format compatible with the one plane. Fortunately, this is + * already what the client gives us. The Vulkan 1.2.184 spec says: + * + * "If image was created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT and + * the image has a multi-planar format, and if + * subresourceRange.aspectMask is VK_IMAGE_ASPECT_PLANE_0_BIT, + * VK_IMAGE_ASPECT_PLANE_1_BIT, or VK_IMAGE_ASPECT_PLANE_2_BIT, format + * must be compatible with the corresponding plane of the image, and the + * sampler to be used with the image view must not enable sampler Y′CBCR + * conversion." + */ + if (image_view->aspects == VK_IMAGE_ASPECT_STENCIL_BIT) { + image_view->format = vk_format_stencil_only(pCreateInfo->format); + } else if (image_view->aspects == VK_IMAGE_ASPECT_DEPTH_BIT) { + image_view->format = vk_format_depth_only(pCreateInfo->format); + } else { + image_view->format = pCreateInfo->format; + } + + image_view->swizzle = (VkComponentMapping) { + .r = remap_swizzle(pCreateInfo->components.r, VK_COMPONENT_SWIZZLE_R), + .g = remap_swizzle(pCreateInfo->components.g, VK_COMPONENT_SWIZZLE_G), + .b = remap_swizzle(pCreateInfo->components.b, VK_COMPONENT_SWIZZLE_B), + .a = remap_swizzle(pCreateInfo->components.a, VK_COMPONENT_SWIZZLE_A), + }; + + assert(range->layerCount > 0); + assert(range->baseMipLevel < image->mip_levels); + + image_view->base_mip_level = range->baseMipLevel; + image_view->level_count = vk_image_subresource_level_count(image, range); + image_view->base_array_layer = range->baseArrayLayer; + image_view->layer_count = vk_image_subresource_layer_count(image, range); + + image_view->extent = + vk_image_mip_level_extent(image, image_view->base_mip_level); + + assert(image_view->base_mip_level + image_view->level_count + <= image->mip_levels); + switch (image->image_type) { + default: + unreachable("bad VkImageType"); + case VK_IMAGE_TYPE_1D: + case VK_IMAGE_TYPE_2D: + assert(image_view->base_array_layer + image_view->layer_count + <= image->array_layers); + break; + case VK_IMAGE_TYPE_3D: + assert(image_view->base_array_layer + image_view->layer_count + <= image_view->extent.depth); + break; + } + + const VkImageUsageFlags image_usage = + vk_image_usage(image, image_view->aspects); + const VkImageViewUsageCreateInfo *usage_info = + vk_find_struct_const(pCreateInfo, IMAGE_VIEW_USAGE_CREATE_INFO); + image_view->usage = usage_info ? usage_info->usage : image_usage; + assert(!(image_view->usage & ~image_usage)); +} + +void +vk_image_view_finish(struct vk_image_view *image_view) +{ + vk_object_base_finish(&image_view->base); +} + +void * +vk_image_view_create(struct vk_device *device, + const VkImageViewCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc, + size_t size) +{ + struct vk_image_view *image_view = + vk_zalloc2(&device->alloc, alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (image_view == NULL) + return NULL; + + vk_image_view_init(device, image_view, pCreateInfo); + + return image_view; +} + +void +vk_image_view_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_image_view *image_view) +{ + vk_object_free(device, alloc, image_view); +} diff --git a/src/vulkan/util/vk_image.h b/src/vulkan/util/vk_image.h index ff8c3523693..b28c6e3c777 100644 --- a/src/vulkan/util/vk_image.h +++ b/src/vulkan/util/vk_image.h @@ -58,6 +58,8 @@ struct vk_image { uint64_t android_external_format; #endif }; +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_image, base, VkImage, + VK_OBJECT_TYPE_IMAGE); void vk_image_init(struct vk_device *device, struct vk_image *image, @@ -107,6 +109,100 @@ vk_image_subresource_level_count(const struct vk_image *image, image->mip_levels - range->baseMipLevel : range->levelCount; } +struct vk_image_view { + struct vk_object_base base; + + VkImageViewCreateFlags create_flags; + struct vk_image *image; + VkImageViewType view_type; + + /** Image view format, relative to the selected aspects + * + * For a depth/stencil image: + * + * - If vk_image_view::aspects contains both depth and stencil, this will + * be the full depth/stencil format of the image. + * + * - If only one aspect is selected, this will be the depth-only or + * stencil-only format, as per the selected aspect. + * + * For color images, we have three cases: + * + * 1. It's a single-plane image in which case this is the unmodified + * format provided to VkImageViewCreateInfo::format. + * + * 2. It's a YCbCr view of a multi-plane image in which case the + * client will have asked for VK_IMAGE_ASPECT_COLOR_BIT and the + * format provided will be the full planar format. In this case, + * the format will be the full format containing all the planes. + * + * 3. It's a single-plane view of a multi-plane image in which case + * the client will have asked for VK_IMAGE_ASPECT_PLANE_N_BIT and + * will have provided a format compatible with that specific + * plane of the multi-planar format. In this case, the format will be + * the plane-compatible format requested by the client. + */ + VkFormat format; + + /* Component mapping, aka swizzle + * + * Unlike the swizzle provided via VkImageViewCreateInfo::components, this + * will never contain VK_COMPONENT_SWIZZLE_IDENTITY. It will be resolved + * to VK_COMPONENT_SWIZZLE_R/G/B/A, as appropriate. + */ + VkComponentMapping swizzle; + + /** Aspects from the image represented by this view + * + * For depth/stencil images, this is the aspectMask provided by + * VkImageViewCreateinfo::subresourceRange::aspectMask. + * + * For color images, we have three cases: + * + * 1. It's a single-plane image in which case this only aspect is + * VK_IMAGE_ASPECT_COLOR_BIT. + * + * 2. It's a YCbCr view of a multi-plane image in which case the + * client will have asked for VK_IMAGE_ASPECT_COLOR_BIT and the + * format provided will be the full planar format. In this case, + * aspects will be the full set of plane aspects in the image. + * + * 3. It's a single-plane view of a multi-plane image in which case + * the client will have asked for VK_IMAGE_ASPECT_PLANE_N_BIT and + * will have provided a format compatible with that specific + * plane of the multi-planar format. In this case, aspects will be + * VK_IMAGE_ASPECT_PLANE_N_BIT where N is the selected plane. + * + * This seems almost backwards from the API but ensures that + * vk_image_view::aspects is always a subset of vk_image::aspects. + */ + VkImageAspectFlags aspects; + + uint32_t base_mip_level; + uint32_t level_count; + uint32_t base_array_layer; + uint32_t layer_count; + + /* Image extent at LOD 0 */ + VkExtent3D extent; + + /* VK_KHR_maintenance2 */ + VkImageUsageFlags usage; +}; + +void vk_image_view_init(struct vk_device *device, + struct vk_image_view *image_view, + const VkImageViewCreateInfo *pCreateInfo); +void vk_image_view_finish(struct vk_image_view *image_view); + +void *vk_image_view_create(struct vk_device *device, + const VkImageViewCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc, + size_t size); +void vk_image_view_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_image_view *image_view); + #ifdef __cplusplus } #endif