vulkan: Provide a vk_image_create_get_format_list() helper
authorBoris Brezillon <boris.brezillon@collabora.com>
Fri, 1 Jul 2022 17:53:34 +0000 (19:53 +0200)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Nov 2022 17:39:46 +0000 (17:39 +0000)
Some drivers need to know the full list of formats that can be used
when VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT or
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT is set (dozen needs
that at least). While VkImageFormatListCreateInfo is a nice way to
get the actual of formats the user intends to use at view creation time,
this paramter is optional, and when it's missing, we need to know the
full list of compatible formats if we want things to work properly.

Provide a helper that hides all the complexity and return a format list
even when VkImageFormatListCreateInfo is missing.

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17339>

src/vulkan/runtime/vk_image.c
src/vulkan/runtime/vk_image.h

index 32a649a..e361d4a 100644 (file)
@@ -33,6 +33,9 @@
 #include "vk_common_entrypoints.h"
 #include "vk_device.h"
 #include "vk_format.h"
+#include "vk_format_info.h"
+#include "vk_log.h"
+#include "vk_physical_device.h"
 #include "vk_render_pass.h"
 #include "vk_util.h"
 #include "vulkan/wsi/wsi_common.h"
@@ -604,6 +607,143 @@ vk_image_layout_is_depth_only(VkImageLayout layout)
    }
 }
 
+static VkResult
+vk_image_create_get_format_list_uncompressed(struct vk_device *device,
+                                             const VkImageCreateInfo *pCreateInfo,
+                                             const VkAllocationCallbacks *pAllocator,
+                                             VkFormat **formats,
+                                             uint32_t *format_count)
+{
+   const struct vk_format_class_info *class =
+      vk_format_get_class_info(pCreateInfo->format);
+
+   *formats = NULL;
+   *format_count = 0;
+
+   if (class->format_count < 2)
+      return VK_SUCCESS;
+
+   *formats = vk_alloc2(&device->alloc, pAllocator,
+                        sizeof(VkFormat) * class->format_count,
+                        alignof(VkFormat), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+   if (*formats == NULL)
+      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   memcpy(*formats, class->formats, sizeof(VkFormat) * class->format_count);
+   *format_count = class->format_count;
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+vk_image_create_get_format_list_compressed(struct vk_device *device,
+                                           const VkImageCreateInfo *pCreateInfo,
+                                           const VkAllocationCallbacks *pAllocator,
+                                           VkFormat **formats,
+                                           uint32_t *format_count)
+{
+   if ((pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) == 0) {
+      return vk_image_create_get_format_list_uncompressed(device,
+                                                          pCreateInfo,
+                                                          pAllocator,
+                                                          formats,
+                                                          format_count);
+   }
+
+   const struct vk_format_class_info *class =
+      vk_format_get_class_info(pCreateInfo->format);
+   const struct vk_format_class_info *uncompr_class = NULL;
+
+   switch (vk_format_get_blocksizebits(pCreateInfo->format)) {
+   case 64:
+      uncompr_class = vk_format_class_get_info(MESA_VK_FORMAT_CLASS_64_BIT);
+      break;
+   case 128:
+      uncompr_class = vk_format_class_get_info(MESA_VK_FORMAT_CLASS_128_BIT);
+      break;
+   }
+
+   if (!uncompr_class)
+      return vk_error(device, VK_ERROR_FORMAT_NOT_SUPPORTED);
+
+   uint32_t fmt_count = class->format_count + uncompr_class->format_count;
+
+   *formats = vk_alloc2(&device->alloc, pAllocator,
+                        sizeof(VkFormat) * fmt_count,
+                        alignof(VkFormat), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+   if (*formats == NULL)
+      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   memcpy(*formats, class->formats, sizeof(VkFormat) * class->format_count);
+   memcpy(*formats + class->format_count, uncompr_class->formats,
+          sizeof(VkFormat) * uncompr_class->format_count);
+   *format_count = class->format_count + uncompr_class->format_count;
+
+   return VK_SUCCESS;
+}
+
+/* Get a list of compatible formats when VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
+ * or VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT is set. This list is
+ * either retrieved from a VkImageFormatListCreateInfo passed to the creation
+ * chain, or forged from the default compatible list specified in the
+ * "formats-compatibility-classes" section of the spec.
+ *
+ * The value returned in *formats must be freed with
+ * vk_free2(&device->alloc, pAllocator), and should not live past the
+ * vkCreateImage() call (allocated in the COMMAND scope).
+ */
+VkResult
+vk_image_create_get_format_list(struct vk_device *device,
+                                const VkImageCreateInfo *pCreateInfo,
+                                const VkAllocationCallbacks *pAllocator,
+                                VkFormat **formats,
+                                uint32_t *format_count)
+{
+   *formats = NULL;
+   *format_count = 0;
+
+   if (!(pCreateInfo->flags &
+         (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |
+          VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT))) {
+      return VK_SUCCESS;
+   }
+
+   /* "Each depth/stencil format is only compatible with itself." */
+   if (vk_format_is_depth_or_stencil(pCreateInfo->format))
+      return VK_SUCCESS;
+
+   const VkImageFormatListCreateInfo *format_list = (const VkImageFormatListCreateInfo *)
+      vk_find_struct_const(pCreateInfo->pNext, IMAGE_FORMAT_LIST_CREATE_INFO);
+
+   if (format_list) {
+      if (!format_list->viewFormatCount)
+         return VK_SUCCESS;
+
+      *formats = vk_alloc2(&device->alloc, pAllocator,
+                           sizeof(VkFormat) * format_list->viewFormatCount,
+                           alignof(VkFormat), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+      if (*formats == NULL)
+         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+      memcpy(*formats, format_list->pViewFormats, sizeof(VkFormat) * format_list->viewFormatCount);
+      *format_count = format_list->viewFormatCount;
+      return VK_SUCCESS;
+   }
+
+   if (vk_format_is_compressed(pCreateInfo->format))
+      return vk_image_create_get_format_list_compressed(device,
+                                                        pCreateInfo,
+                                                        pAllocator,
+                                                        formats,
+                                                        format_count);
+
+   return vk_image_create_get_format_list_uncompressed(device,
+                                                       pCreateInfo,
+                                                       pAllocator,
+                                                       formats,
+                                                       format_count);
+}
+
 /* From the Vulkan Specification 1.2.166 - VkAttachmentReference2:
  *
  *   "If layout only specifies the layout of the depth aspect of the
index 2077c3b..6557a45 100644 (file)
@@ -90,6 +90,13 @@ void vk_image_destroy(struct vk_device *device,
                       const VkAllocationCallbacks *alloc,
                       struct vk_image *image);
 
+VkResult
+vk_image_create_get_format_list(struct vk_device *device,
+                                const VkImageCreateInfo *pCreateInfo,
+                                const VkAllocationCallbacks *pAllocator,
+                                VkFormat **formats,
+                                uint32_t *format_count);
+
 void vk_image_set_format(struct vk_image *image, VkFormat format);
 
 VkImageUsageFlags vk_image_usage(const struct vk_image *image,