/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2024 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include "vk_resources.h"
#include "maths/vec.h"
#include "vk_info.h"

WRAPPED_POOL_INST(WrappedVkInstance)
WRAPPED_POOL_INST(WrappedVkPhysicalDevice)
WRAPPED_POOL_INST(WrappedVkDevice)
WRAPPED_POOL_INST(WrappedVkQueue)
WRAPPED_POOL_INST(WrappedVkCommandBuffer)
WRAPPED_POOL_INST(WrappedVkFence)
WRAPPED_POOL_INST(WrappedVkDeviceMemory)
WRAPPED_POOL_INST(WrappedVkBuffer)
WRAPPED_POOL_INST(WrappedVkImage)
WRAPPED_POOL_INST(WrappedVkSemaphore)
WRAPPED_POOL_INST(WrappedVkEvent)
WRAPPED_POOL_INST(WrappedVkQueryPool)
WRAPPED_POOL_INST(WrappedVkBufferView)
WRAPPED_POOL_INST(WrappedVkImageView)
WRAPPED_POOL_INST(WrappedVkShaderModule)
WRAPPED_POOL_INST(WrappedVkPipelineCache)
WRAPPED_POOL_INST(WrappedVkPipelineLayout)
WRAPPED_POOL_INST(WrappedVkRenderPass)
WRAPPED_POOL_INST(WrappedVkPipeline)
WRAPPED_POOL_INST(WrappedVkDescriptorSetLayout)
WRAPPED_POOL_INST(WrappedVkSampler)
WRAPPED_POOL_INST(WrappedVkDescriptorPool)
WRAPPED_POOL_INST(WrappedVkDescriptorSet)
WRAPPED_POOL_INST(WrappedVkFramebuffer)
WRAPPED_POOL_INST(WrappedVkCommandPool)
WRAPPED_POOL_INST(WrappedVkSwapchainKHR)
WRAPPED_POOL_INST(WrappedVkSurfaceKHR)
WRAPPED_POOL_INST(WrappedVkDescriptorUpdateTemplate)
WRAPPED_POOL_INST(WrappedVkSamplerYcbcrConversion)
WRAPPED_POOL_INST(WrappedVkAccelerationStructureKHR)

byte VkResourceRecord::markerValue[32] = {
    0xaa, 0xbb, 0xcc, 0xdd, 0x88, 0x77, 0x66, 0x55, 0x01, 0x23, 0x45, 0x67, 0x98, 0x76, 0x54, 0x32,
};

bool IsDispatchableRes(WrappedVkRes *ptr)
{
  return (WrappedVkPhysicalDevice::IsAlloc(ptr) || WrappedVkInstance::IsAlloc(ptr) ||
          WrappedVkDevice::IsAlloc(ptr) || WrappedVkQueue::IsAlloc(ptr) ||
          WrappedVkCommandBuffer::IsAlloc(ptr));
}

bool IsPostponableRes(const WrappedVkRes *ptr)
{
  // only memory and images are postponed
  if(WrappedVkDeviceMemory::IsAlloc(ptr) || WrappedVkImage::IsAlloc(ptr))
  {
    // and only if they're not storable. If they are storable they may have been written recently in
    // a descriptor set binding and we didn't track it (since descriptor updates can be too
    // high-frequency to be worth tracking), so pessimistically we don't postpone.
    return !((WrappedVkNonDispRes *)ptr)->record->storable;
  }

  return false;
}

VkResourceType IdentifyTypeByPtr(WrappedVkRes *ptr)
{
  if(WrappedVkPhysicalDevice::IsAlloc(ptr))
    return eResPhysicalDevice;
  if(WrappedVkInstance::IsAlloc(ptr))
    return eResInstance;
  if(WrappedVkDevice::IsAlloc(ptr))
    return eResDevice;
  if(WrappedVkQueue::IsAlloc(ptr))
    return eResQueue;
  if(WrappedVkDeviceMemory::IsAlloc(ptr))
    return eResDeviceMemory;
  if(WrappedVkBuffer::IsAlloc(ptr))
    return eResBuffer;
  if(WrappedVkBufferView::IsAlloc(ptr))
    return eResBufferView;
  if(WrappedVkImage::IsAlloc(ptr))
    return eResImage;
  if(WrappedVkImageView::IsAlloc(ptr))
    return eResImageView;
  if(WrappedVkFramebuffer::IsAlloc(ptr))
    return eResFramebuffer;
  if(WrappedVkRenderPass::IsAlloc(ptr))
    return eResRenderPass;
  if(WrappedVkShaderModule::IsAlloc(ptr))
    return eResShaderModule;
  if(WrappedVkPipelineCache::IsAlloc(ptr))
    return eResPipelineCache;
  if(WrappedVkPipelineLayout::IsAlloc(ptr))
    return eResPipelineLayout;
  if(WrappedVkPipeline::IsAlloc(ptr))
    return eResPipeline;
  if(WrappedVkSampler::IsAlloc(ptr))
    return eResSampler;
  if(WrappedVkDescriptorPool::IsAlloc(ptr))
    return eResDescriptorPool;
  if(WrappedVkDescriptorSetLayout::IsAlloc(ptr))
    return eResDescriptorSetLayout;
  if(WrappedVkDescriptorSet::IsAlloc(ptr))
    return eResDescriptorSet;
  if(WrappedVkCommandPool::IsAlloc(ptr))
    return eResCommandPool;
  if(WrappedVkCommandBuffer::IsAlloc(ptr))
    return eResCommandBuffer;
  if(WrappedVkFence::IsAlloc(ptr))
    return eResFence;
  if(WrappedVkEvent::IsAlloc(ptr))
    return eResEvent;
  if(WrappedVkQueryPool::IsAlloc(ptr))
    return eResQueryPool;
  if(WrappedVkSemaphore::IsAlloc(ptr))
    return eResSemaphore;
  if(WrappedVkSwapchainKHR::IsAlloc(ptr))
    return eResSwapchain;
  if(WrappedVkSurfaceKHR::IsAlloc(ptr))
    return eResSurface;
  if(WrappedVkDescriptorUpdateTemplate::IsAlloc(ptr))
    return eResDescUpdateTemplate;
  if(WrappedVkSamplerYcbcrConversion::IsAlloc(ptr))
    return eResSamplerConversion;
  if(WrappedVkAccelerationStructureKHR::IsAlloc(ptr))
    return eResAccelerationStructureKHR;

  RDCERR("Unknown type for ptr 0x%p", ptr);

  return eResUnknown;
}

bool IsBlockFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC4_SNORM_BLOCK:
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK:
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK:
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return true;
    default: break;
  }

  return false;
}

bool IsDepthOrStencilFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_D16_UNORM:
    case VK_FORMAT_X8_D24_UNORM_PACK32:
    case VK_FORMAT_D32_SFLOAT:
    case VK_FORMAT_S8_UINT:
    case VK_FORMAT_D16_UNORM_S8_UINT:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT_S8_UINT: return true;
    default: break;
  }

  return false;
}

bool IsDepthAndStencilFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_D16_UNORM_S8_UINT:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT_S8_UINT: return true;
    default: break;
  }

  return false;
}

bool IsStencilFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_S8_UINT:
    case VK_FORMAT_D16_UNORM_S8_UINT:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT_S8_UINT: return true;
    default: break;
  }

  return false;
}

bool IsDepthOnlyFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_D16_UNORM:
    case VK_FORMAT_X8_D24_UNORM_PACK32:
    case VK_FORMAT_D32_SFLOAT: return true;
    default: break;
  }

  return false;
}

bool IsStencilOnlyFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_S8_UINT: return true;
    default: break;
  }

  return false;
}

bool IsSRGBFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_R8_SRGB:
    case VK_FORMAT_R8G8_SRGB:
    case VK_FORMAT_R8G8B8_SRGB:
    case VK_FORMAT_B8G8R8_SRGB:
    case VK_FORMAT_R8G8B8A8_SRGB:
    case VK_FORMAT_B8G8R8A8_SRGB:
    case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return true;
    default: break;
  }

  return false;
}

bool Is64BitFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_R64_SFLOAT:
    case VK_FORMAT_R64G64_SFLOAT:
    case VK_FORMAT_R64G64B64_SFLOAT:
    case VK_FORMAT_R64G64B64A64_SFLOAT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64A64_SINT:
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64A64_UINT: return true;
    default: break;
  }

  return false;
}

bool IsUIntFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_R8_UINT:
    case VK_FORMAT_R8G8_UINT:
    case VK_FORMAT_R8G8B8_UINT:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_R8G8B8A8_UINT:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
    case VK_FORMAT_R16_UINT:
    case VK_FORMAT_R16G16_UINT:
    case VK_FORMAT_R16G16B16_UINT:
    case VK_FORMAT_R16G16B16A16_UINT:
    case VK_FORMAT_R32_UINT:
    case VK_FORMAT_R32G32_UINT:
    case VK_FORMAT_R32G32B32_UINT:
    case VK_FORMAT_R32G32B32A32_UINT:
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64A64_UINT: return true;
    default: break;
  }

  return false;
}

bool IsSIntFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_R8_SINT:
    case VK_FORMAT_R8G8_SINT:
    case VK_FORMAT_R8G8B8_SINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_R8G8B8A8_SINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
    case VK_FORMAT_R16_SINT:
    case VK_FORMAT_R16G16_SINT:
    case VK_FORMAT_R16G16B16_SINT:
    case VK_FORMAT_R16G16B16A16_SINT:
    case VK_FORMAT_R32_SINT:
    case VK_FORMAT_R32G32_SINT:
    case VK_FORMAT_R32G32B32_SINT:
    case VK_FORMAT_R32G32B32A32_SINT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64A64_SINT: return true;
    default: break;
  }

  return false;
}

bool IsYUVFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_R12X4_UNORM_PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: return true;
    default: break;
  }

  return false;
}

uint32_t GetYUVPlaneCount(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: return 2;
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return 3;

    default: break;
  }

  return 1;
}

uint32_t GetYUVNumRows(VkFormat f, uint32_t height)
{
  switch(f)
  {
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
      // all of these are 4:2:0, so number of rows is equal to height + height/2
      return height + height / 2;
    default: break;
  }

  return height;
}

VkFormat GetYUVViewPlaneFormat(VkFormat f, uint32_t plane)
{
  switch(f)
  {
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_R12X4_UNORM_PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM: return f;
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: return VK_FORMAT_R8_UNORM;
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
      return plane == 0 ? VK_FORMAT_R8_UNORM : VK_FORMAT_R8G8_UNORM;
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: return VK_FORMAT_R10X6_UNORM_PACK16;
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
      return plane == 0 ? VK_FORMAT_R10X6_UNORM_PACK16 : VK_FORMAT_R10X6G10X6_UNORM_2PACK16;
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: return VK_FORMAT_R12X4_UNORM_PACK16;
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
      return plane == 0 ? VK_FORMAT_R12X4_UNORM_PACK16 : VK_FORMAT_R12X4G12X4_UNORM_2PACK16;
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return VK_FORMAT_R16_UNORM;
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
      return plane == 0 ? VK_FORMAT_R16_UNORM : VK_FORMAT_R16G16_UNORM;

    default: break;
  }

  return f;
}

void GetYUVShaderParameters(VkFormat f, Vec4u &YUVDownsampleRate, Vec4u &YUVAChannels)
{
  if(IsYUVFormat(f))
  {
    ResourceFormat fmt = MakeResourceFormat(f);

    switch(fmt.YUVSubsampling())
    {
      case 444:
        YUVDownsampleRate.x = 1;
        YUVDownsampleRate.y = 1;
        break;
      case 422:
        YUVDownsampleRate.x = 2;
        YUVDownsampleRate.y = 1;
        break;
      case 420:
        YUVDownsampleRate.x = 2;
        YUVDownsampleRate.y = 2;
        break;
      default: break;
    }
    YUVDownsampleRate.z = fmt.YUVPlaneCount();
    switch(fmt.type)
    {
      case ResourceFormatType::YUV8: YUVDownsampleRate.w = 8; break;
      case ResourceFormatType::YUV10: YUVDownsampleRate.w = 10; break;
      case ResourceFormatType::YUV12: YUVDownsampleRate.w = 12; break;
      case ResourceFormatType::YUV16: YUVDownsampleRate.w = 16; break;
      default: break;
    }
    switch(f)
    {
      case VK_FORMAT_G8B8G8R8_422_UNORM: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_B8G8R8G8_422_UNORM: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: YUVAChannels = {0, 4, 8, 0xff}; break;
      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: YUVAChannels = {0, 4, 5, 0xff}; break;
      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: YUVAChannels = {0, 4, 8, 0xff}; break;
      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: YUVAChannels = {0, 4, 5, 0xff}; break;
      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: YUVAChannels = {0, 4, 8, 0xff}; break;
      case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: YUVAChannels = {0, 4, 5, 0xff}; break;
      case VK_FORMAT_R10X6_UNORM_PACK16: YUVAChannels = {0, 0xff, 0xff, 0xff}; break;
      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: YUVAChannels = {0xff, 0, 1, 0xff}; break;
      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: YUVAChannels = {1, 2, 0, 3}; break;
      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
        YUVAChannels = {0, 4, 8, 0xff};
        break;
      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
        YUVAChannels = {0, 4, 5, 0xff};
        break;
      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
        YUVAChannels = {0, 4, 8, 0xff};
        break;
      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
        YUVAChannels = {0, 4, 5, 0xff};
        break;
      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
        YUVAChannels = {0, 4, 8, 0xff};
        break;
      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
        YUVAChannels = {0, 4, 5, 0xff};
        break;
      case VK_FORMAT_R12X4_UNORM_PACK16: YUVAChannels = {0, 0xff, 0xff, 0xff}; break;
      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: YUVAChannels = {0xff, 0, 1, 0xff}; break;
      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: YUVAChannels = {1, 2, 0, 3}; break;
      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
        YUVAChannels = {0, 4, 8, 0xff};
        break;
      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
        YUVAChannels = {0, 4, 5, 0xff};
        break;
      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
        YUVAChannels = {0, 4, 8, 0xff};
        break;
      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
        YUVAChannels = {0, 4, 5, 0xff};
        break;
      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
        YUVAChannels = {0, 4, 8, 0xff};
        break;
      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
        YUVAChannels = {0, 4, 5, 0xff};
        break;
      case VK_FORMAT_G16B16G16R16_422_UNORM: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_B16G16R16G16_422_UNORM: YUVAChannels = {0, 2, 1, 0xff}; break;
      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: YUVAChannels = {0, 4, 8, 0xff}; break;
      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: YUVAChannels = {0, 4, 5, 0xff}; break;
      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: YUVAChannels = {0, 4, 8, 0xff}; break;
      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: YUVAChannels = {0, 4, 5, 0xff}; break;
      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: YUVAChannels = {0, 4, 8, 0xff}; break;
      case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: YUVAChannels = {0, 4, 5, 0xff}; break;
      default: break;
    }
  }
}

VkFormat GetDepthOnlyFormat(VkFormat f)
{
  switch(f)
  {
    case VK_FORMAT_D16_UNORM_S8_UINT: return VK_FORMAT_D16_UNORM;
    case VK_FORMAT_D24_UNORM_S8_UINT: return VK_FORMAT_X8_D24_UNORM_PACK32;
    case VK_FORMAT_D32_SFLOAT_S8_UINT: return VK_FORMAT_D32_SFLOAT;
    default: break;
  }

  return f;
}

VkFormat GetViewCastedFormat(VkFormat f, CompType typeCast)
{
  if(typeCast == CompType::Typeless)
    return f;

  switch(f)
  {
    case VK_FORMAT_R64G64B64A64_UINT:
    case VK_FORMAT_R64G64B64A64_SINT:
    case VK_FORMAT_R64G64B64A64_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R64G64B64A64_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R64G64B64A64_SINT;
      else
        return VK_FORMAT_R64G64B64A64_SFLOAT;
    }
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R64G64B64_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R64G64B64_SINT;
      else
        return VK_FORMAT_R64G64B64_SFLOAT;
    }
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R64G64_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R64G64_SINT;
      else
        return VK_FORMAT_R64G64_SFLOAT;
    }
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R64_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R64_SINT;
      else
        return VK_FORMAT_R64_SFLOAT;
    }
    case VK_FORMAT_R32G32B32A32_UINT:
    case VK_FORMAT_R32G32B32A32_SINT:
    case VK_FORMAT_R32G32B32A32_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R32G32B32A32_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R32G32B32A32_SINT;
      else
        return VK_FORMAT_R32G32B32A32_SFLOAT;
    }
    case VK_FORMAT_R32G32B32_UINT:
    case VK_FORMAT_R32G32B32_SINT:
    case VK_FORMAT_R32G32B32_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R32G32B32_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R32G32B32_SINT;
      else
        return VK_FORMAT_R32G32B32_SFLOAT;
    }
    case VK_FORMAT_R32G32_UINT:
    case VK_FORMAT_R32G32_SINT:
    case VK_FORMAT_R32G32_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R32G32_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R32G32_SINT;
      else
        return VK_FORMAT_R32G32_SFLOAT;
    }
    case VK_FORMAT_R32_UINT:
    case VK_FORMAT_R32_SINT:
    case VK_FORMAT_R32_SFLOAT:
    case VK_FORMAT_D32_SFLOAT:
    {
      if(typeCast == CompType::UInt)
        return VK_FORMAT_R32_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R32_SINT;
      else if(typeCast == CompType::Depth)
        return VK_FORMAT_D32_SFLOAT;
      else
        return VK_FORMAT_R32_SFLOAT;
    }
    case VK_FORMAT_R16G16B16A16_UNORM:
    case VK_FORMAT_R16G16B16A16_SNORM:
    case VK_FORMAT_R16G16B16A16_USCALED:
    case VK_FORMAT_R16G16B16A16_SSCALED:
    case VK_FORMAT_R16G16B16A16_UINT:
    case VK_FORMAT_R16G16B16A16_SINT:
    case VK_FORMAT_R16G16B16A16_SFLOAT:
    {
      if(typeCast == CompType::UNorm || typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R16G16B16A16_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R16G16B16A16_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R16G16B16A16_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R16G16B16A16_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R16G16B16A16_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R16G16B16A16_SINT;
      else
        return VK_FORMAT_R16G16B16A16_SFLOAT;
    }
    case VK_FORMAT_R16G16B16_UNORM:
    case VK_FORMAT_R16G16B16_SNORM:
    case VK_FORMAT_R16G16B16_USCALED:
    case VK_FORMAT_R16G16B16_SSCALED:
    case VK_FORMAT_R16G16B16_UINT:
    case VK_FORMAT_R16G16B16_SINT:
    case VK_FORMAT_R16G16B16_SFLOAT:
    {
      if(typeCast == CompType::UNorm || typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R16G16B16_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R16G16B16_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R16G16B16_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R16G16B16_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R16G16B16_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R16G16B16_SINT;
      else
        return VK_FORMAT_R16G16B16_SFLOAT;
    }
    case VK_FORMAT_R16G16_UNORM:
    case VK_FORMAT_R16G16_SNORM:
    case VK_FORMAT_R16G16_USCALED:
    case VK_FORMAT_R16G16_SSCALED:
    case VK_FORMAT_R16G16_UINT:
    case VK_FORMAT_R16G16_SINT:
    case VK_FORMAT_R16G16_SFLOAT:
    {
      if(typeCast == CompType::UNorm || typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R16G16_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R16G16_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R16G16_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R16G16_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R16G16_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R16G16_SINT;
      else
        return VK_FORMAT_R16G16_SFLOAT;
    }
    case VK_FORMAT_R16_UNORM:
    case VK_FORMAT_R16_SNORM:
    case VK_FORMAT_R16_USCALED:
    case VK_FORMAT_R16_SSCALED:
    case VK_FORMAT_R16_UINT:
    case VK_FORMAT_R16_SINT:
    case VK_FORMAT_R16_SFLOAT:
    case VK_FORMAT_D16_UNORM:
    {
      if(typeCast == CompType::UNorm || typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R16_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R16_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R16_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R16_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R16_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R16_SINT;
      else if(typeCast == CompType::Depth)
        return VK_FORMAT_D16_UNORM;
      else
        return VK_FORMAT_R16_SFLOAT;
    }
    case VK_FORMAT_R8G8B8A8_UNORM:
    case VK_FORMAT_R8G8B8A8_SNORM:
    case VK_FORMAT_R8G8B8A8_USCALED:
    case VK_FORMAT_R8G8B8A8_SSCALED:
    case VK_FORMAT_R8G8B8A8_UINT:
    case VK_FORMAT_R8G8B8A8_SINT:
    case VK_FORMAT_R8G8B8A8_SRGB:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_R8G8B8A8_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R8G8B8A8_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R8G8B8A8_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R8G8B8A8_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R8G8B8A8_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R8G8B8A8_SINT;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R8G8B8A8_SRGB;
      else
        return VK_FORMAT_R8G8B8A8_UNORM;
    }
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_B8G8R8A8_SNORM:
    case VK_FORMAT_B8G8R8A8_USCALED:
    case VK_FORMAT_B8G8R8A8_SSCALED:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_B8G8R8A8_SRGB:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_B8G8R8A8_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_B8G8R8A8_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_B8G8R8A8_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_B8G8R8A8_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_B8G8R8A8_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_B8G8R8A8_SINT;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_B8G8R8A8_SRGB;
      else
        return VK_FORMAT_B8G8R8A8_UNORM;
    }
    case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_A8B8G8R8_SNORM_PACK32;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_A8B8G8R8_USCALED_PACK32;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_A8B8G8R8_SSCALED_PACK32;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_A8B8G8R8_UINT_PACK32;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_A8B8G8R8_SINT_PACK32;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_A8B8G8R8_SRGB_PACK32;
      else
        return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
    }
    case VK_FORMAT_R8G8B8_UNORM:
    case VK_FORMAT_R8G8B8_SNORM:
    case VK_FORMAT_R8G8B8_USCALED:
    case VK_FORMAT_R8G8B8_SSCALED:
    case VK_FORMAT_R8G8B8_UINT:
    case VK_FORMAT_R8G8B8_SINT:
    case VK_FORMAT_R8G8B8_SRGB:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_R8G8B8_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R8G8B8_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R8G8B8_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R8G8B8_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R8G8B8_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R8G8B8_SINT;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R8G8B8_SRGB;
      else
        return VK_FORMAT_R8G8B8_UNORM;
    }
    case VK_FORMAT_B8G8R8_UNORM:
    case VK_FORMAT_B8G8R8_SNORM:
    case VK_FORMAT_B8G8R8_USCALED:
    case VK_FORMAT_B8G8R8_SSCALED:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_B8G8R8_SRGB:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_B8G8R8_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_B8G8R8_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_B8G8R8_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_B8G8R8_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_B8G8R8_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_B8G8R8_SINT;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_B8G8R8_SRGB;
      else
        return VK_FORMAT_B8G8R8_UNORM;
    }
    case VK_FORMAT_R8G8_UNORM:
    case VK_FORMAT_R8G8_SNORM:
    case VK_FORMAT_R8G8_USCALED:
    case VK_FORMAT_R8G8_SSCALED:
    case VK_FORMAT_R8G8_UINT:
    case VK_FORMAT_R8G8_SINT:
    case VK_FORMAT_R8G8_SRGB:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_R8G8_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R8G8_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R8G8_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R8G8_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R8G8_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R8G8_SINT;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R8G8_SRGB;
      else
        return VK_FORMAT_R8G8_UNORM;
    }
    case VK_FORMAT_R8_UNORM:
    case VK_FORMAT_R8_SNORM:
    case VK_FORMAT_R8_USCALED:
    case VK_FORMAT_R8_SSCALED:
    case VK_FORMAT_R8_UINT:
    case VK_FORMAT_R8_SINT:
    case VK_FORMAT_R8_SRGB:
    case VK_FORMAT_S8_UINT:
    {
      if(typeCast == CompType::UNorm)
        return VK_FORMAT_R8_UNORM;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_R8_SNORM;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_R8_USCALED;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_R8_SSCALED;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_R8_UINT;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_R8_SINT;
      else if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_R8_SRGB;
      else if(typeCast == CompType::Depth)
        return VK_FORMAT_S8_UINT;
      else
        return VK_FORMAT_R8_UNORM;
    }
    case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
    {
      if(typeCast == CompType::UNorm || typeCast == CompType::UNormSRGB)
        return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_A2B10G10R10_SNORM_PACK32;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_A2B10G10R10_USCALED_PACK32;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_A2B10G10R10_SSCALED_PACK32;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_A2B10G10R10_UINT_PACK32;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_A2B10G10R10_SINT_PACK32;
      else
        return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
    }
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    {
      if(typeCast == CompType::UNorm || typeCast == CompType::UNormSRGB)
        return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
      else if(typeCast == CompType::SNorm)
        return VK_FORMAT_A2R10G10B10_SNORM_PACK32;
      else if(typeCast == CompType::UScaled)
        return VK_FORMAT_A2R10G10B10_USCALED_PACK32;
      else if(typeCast == CompType::SScaled)
        return VK_FORMAT_A2R10G10B10_SSCALED_PACK32;
      else if(typeCast == CompType::UInt)
        return VK_FORMAT_A2R10G10B10_UINT_PACK32;
      else if(typeCast == CompType::SInt)
        return VK_FORMAT_A2R10G10B10_SINT_PACK32;
      else
        return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
    }
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_BC1_RGB_SRGB_BLOCK
                                               : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_BC1_RGBA_SRGB_BLOCK
                                               : VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC4_SNORM_BLOCK:
      return (typeCast == CompType::SNorm) ? VK_FORMAT_BC4_SNORM_BLOCK : VK_FORMAT_BC4_UNORM_BLOCK;
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK
                                               : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK
                                               : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK
                                               : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK:
      return (typeCast == CompType::SNorm) ? VK_FORMAT_EAC_R11_SNORM_BLOCK
                                           : VK_FORMAT_EAC_R11_UNORM_BLOCK;
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
      return (typeCast == CompType::SNorm) ? VK_FORMAT_EAC_R11G11_SNORM_BLOCK
                                           : VK_FORMAT_EAC_R11G11_UNORM_BLOCK;
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK:
      return (typeCast == CompType::SNorm) ? VK_FORMAT_BC5_SNORM_BLOCK : VK_FORMAT_BC5_UNORM_BLOCK;
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK:
      return (typeCast == CompType::SNorm) ? VK_FORMAT_BC6H_SFLOAT_BLOCK
                                           : VK_FORMAT_BC6H_UFLOAT_BLOCK;
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_4x4_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_5x4_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_5x5_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_6x5_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_6x6_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_8x5_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_8x6_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_8x8_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_10x5_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_10x6_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_10x8_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_10x10_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_12x10_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
    }
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
    {
      if(typeCast == CompType::UNormSRGB)
        return VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
      else if(typeCast == CompType::Float)
        return VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK;
      else
        return VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
    }
    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG
                                               : VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG
                                               : VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG;
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG
                                               : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
      return (typeCast == CompType::UNormSRGB) ? VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG
                                               : VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG;

    // all other formats have no aliases so nothing to typecast
    default: break;
  }

  return f;
}

BlockShape GetBlockShape(VkFormat Format, uint32_t plane)
{
  switch(Format)
  {
    case VK_FORMAT_R64G64B64A64_UINT:
    case VK_FORMAT_R64G64B64A64_SINT:
    case VK_FORMAT_R64G64B64A64_SFLOAT: return {1, 1, 32};
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64_SFLOAT: return {1, 1, 24};
    case VK_FORMAT_R32G32B32A32_UINT:
    case VK_FORMAT_R32G32B32A32_SINT:
    case VK_FORMAT_R32G32B32A32_SFLOAT:
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64_SFLOAT: return {1, 1, 16};
    case VK_FORMAT_R32G32B32_UINT:
    case VK_FORMAT_R32G32B32_SINT:
    case VK_FORMAT_R32G32B32_SFLOAT: return {1, 1, 12};
    case VK_FORMAT_R16G16B16A16_UNORM:
    case VK_FORMAT_R16G16B16A16_SNORM:
    case VK_FORMAT_R16G16B16A16_USCALED:
    case VK_FORMAT_R16G16B16A16_SSCALED:
    case VK_FORMAT_R16G16B16A16_UINT:
    case VK_FORMAT_R16G16B16A16_SINT:
    case VK_FORMAT_R16G16B16A16_SFLOAT:
    case VK_FORMAT_R32G32_UINT:
    case VK_FORMAT_R32G32_SINT:
    case VK_FORMAT_R32G32_SFLOAT:
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64_SFLOAT: return {1, 1, 8};
    case VK_FORMAT_R16G16B16_UNORM:
    case VK_FORMAT_R16G16B16_SNORM:
    case VK_FORMAT_R16G16B16_USCALED:
    case VK_FORMAT_R16G16B16_SSCALED:
    case VK_FORMAT_R16G16B16_UINT:
    case VK_FORMAT_R16G16B16_SINT:
    case VK_FORMAT_R16G16B16_SFLOAT: return {1, 1, 6};
    case VK_FORMAT_D32_SFLOAT_S8_UINT: return {1, 1, 8};
    case VK_FORMAT_R8G8B8_UNORM:
    case VK_FORMAT_R8G8B8_SNORM:
    case VK_FORMAT_R8G8B8_USCALED:
    case VK_FORMAT_R8G8B8_SSCALED:
    case VK_FORMAT_R8G8B8_UINT:
    case VK_FORMAT_R8G8B8_SINT:
    case VK_FORMAT_R8G8B8_SRGB:
    case VK_FORMAT_B8G8R8_UNORM:
    case VK_FORMAT_B8G8R8_SNORM:
    case VK_FORMAT_B8G8R8_USCALED:
    case VK_FORMAT_B8G8R8_SSCALED:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_B8G8R8_SRGB: return {1, 1, 3};
    case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
    case VK_FORMAT_R8G8B8A8_UNORM:
    case VK_FORMAT_R8G8B8A8_SNORM:
    case VK_FORMAT_R8G8B8A8_USCALED:
    case VK_FORMAT_R8G8B8A8_SSCALED:
    case VK_FORMAT_R8G8B8A8_UINT:
    case VK_FORMAT_R8G8B8A8_SINT:
    case VK_FORMAT_R8G8B8A8_SRGB:
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_B8G8R8A8_SNORM:
    case VK_FORMAT_B8G8R8A8_USCALED:
    case VK_FORMAT_B8G8R8A8_SSCALED:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_B8G8R8A8_SRGB:
    case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
    case VK_FORMAT_R16G16_UNORM:
    case VK_FORMAT_R16G16_SNORM:
    case VK_FORMAT_R16G16_USCALED:
    case VK_FORMAT_R16G16_SSCALED:
    case VK_FORMAT_R16G16_UINT:
    case VK_FORMAT_R16G16_SINT:
    case VK_FORMAT_R16G16_SFLOAT:
    case VK_FORMAT_R32_UINT:
    case VK_FORMAT_R32_SINT:
    case VK_FORMAT_R32_SFLOAT:
    case VK_FORMAT_X8_D24_UNORM_PACK32:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT:
    case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: return {1, 1, 4};
    case VK_FORMAT_D16_UNORM_S8_UINT: return {1, 1, 4};
    case VK_FORMAT_R8G8_UNORM:
    case VK_FORMAT_R8G8_SNORM:
    case VK_FORMAT_R8G8_USCALED:
    case VK_FORMAT_R8G8_SSCALED:
    case VK_FORMAT_R8G8_UINT:
    case VK_FORMAT_R8G8_SINT:
    case VK_FORMAT_R8G8_SRGB:
    case VK_FORMAT_R16_UNORM:
    case VK_FORMAT_R16_SNORM:
    case VK_FORMAT_R16_USCALED:
    case VK_FORMAT_R16_SSCALED:
    case VK_FORMAT_R16_UINT:
    case VK_FORMAT_R16_SINT:
    case VK_FORMAT_R16_SFLOAT:
    case VK_FORMAT_D16_UNORM:
    case VK_FORMAT_R5G6B5_UNORM_PACK16:
    case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
    case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
    case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
    case VK_FORMAT_B5G6R5_UNORM_PACK16:
    case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
    case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
    case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
    case VK_FORMAT_B4G4R4A4_UNORM_PACK16: return {1, 1, 2};
    case VK_FORMAT_R4G4_UNORM_PACK8:
    case VK_FORMAT_R8_UNORM:
    case VK_FORMAT_R8_SNORM:
    case VK_FORMAT_R8_USCALED:
    case VK_FORMAT_R8_SSCALED:
    case VK_FORMAT_R8_UINT:
    case VK_FORMAT_R8_SINT:
    case VK_FORMAT_R8_SRGB:
    case VK_FORMAT_S8_UINT: return {1, 1, 1};
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC4_SNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK: return {4, 4, 8};
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK:
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK:
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: return {4, 4, 16};
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: return {4, 4, 16};
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: return {5, 4, 16};
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: return {5, 5, 16};
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: return {6, 5, 16};
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: return {6, 6, 16};
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: return {8, 5, 16};
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: return {8, 6, 16};
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: return {8, 8, 16};
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: return {10, 5, 16};
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: return {10, 6, 16};
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: return {10, 8, 16};
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: return {10, 10, 16};
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: return {12, 10, 16};
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: return {12, 12, 16};

    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return {8, 4, 8};
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return {4, 4, 8};

    /*
     * YUV planar/packed subsampled textures.
     *
     * In each diagram we indicate (maybe part) of the data for a 4x4 texture:
     *
     * +---+---+---+---+
     * | 0 | 1 | 2 | 3 |
     * +---+---+---+---+
     * | 4 | 5 | 6 | 7 |
     * +---+---+---+---+
     * | 8 | 9 | A | B |
     * +---+---+---+---+
     * | C | D | E | F |
     * +---+---+---+---+
     *
     *
     * FOURCC decoding:
     *  - char 0: 'Y' = packed, 'P' = planar
     *  - char 1: '4' = 4:4:4, '2' = 4:2:2, '1' = 4:2:1, '0' = 4:2:0
     *  - char 2+3: '16' = 16-bit, '10' = 10-bit, '08' = 8-bit
     *
     * planar = Y is first, all together, then UV comes second.
     * packed = YUV is interleaved
     *
     * ======================= 4:4:4 lossless packed =========================
     *
     * Equivalent to uncompressed formats, just YUV instead of RGB. For 8-bit:
     *
     * pixel:      0            1            2            3
     * byte:  0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F
     *        Y0 U0 V0 A0  Y1 U1 V1 A1  Y2 U2 V2 A2  Y3 U3 V3 A3
     *
     * 16-bit is similar with two bytes per sample, 10-bit for uncompressed is
     * equivalent to R10G10B10A2 but with RGB=>YUV
     *
     * ============================ 4:2:2 packed =============================
     *
     * 50% horizontal subsampling packed, two Y samples for each U/V sample pair. For 8-bit:
     *
     * pixel:   0  |  1      2  |  3      4  |  5      6  |  7
     * byte:  0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F
     *        Y0 U0 Y1 V0  Y2 U1 Y3 V1  Y4 U2 Y5 V2  Y6 U3 Y7 V3
     *
     * 16-bit is similar with two bytes per sample, 10-bit is stored identically to 16-bit but in
     * the most significant bits:
     *
     * bit:    FEDCBA9876543210
     * 16-bit: XXXXXXXXXXXXXXXX
     * 10-bit: XXXXXXXXXX000000
     *
     * Since the data is unorm this just spaces out valid values.
     *
     * ============================ 4:2:0 planar =============================
     *
     * 50% horizontal and vertical subsampled planar, four Y samples for each U/V sample pair.
     * For 8-bit:
     *
     *
     * pixel: 0  1  2  3   4  5  6  7
     * byte:  0  1  2  3   4  5  6  7
     *        Y0 Y1 Y2 Y3  Y4 Y5 Y6 Y7
     *
     * pixel: 8  9  A  B   C  D  E  F
     * byte:  8  9  A  B   C  D  E  F
     *        Y8 Y9 Ya Yb  Yc Yd Ye Yf
     *
     *        ... all of the rest of Y luma ...
     *
     * pixel:  T&4 | 1&5    2&6 | 3&7
     * byte:  0  1  2  3   4  5  6  7
     *        U0 V0 U1 V1  U2 V2 U3 V3
     *
     * pixel:  8&C | 9&D    A&E | B&F
     * byte:  8  9  A  B   C  D  E  F
     *        U4 V4 U5 V5  U6 V6 U7 V7
     */
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
      // 4:2:2 packed 8-bit, so 1 byte per pixel for luma and 1 byte per pixel for chroma (2 chroma
      // samples, with 50% subsampling = 1 byte per pixel)
      return {2, 1, 4};
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: return {1, 1, 1};
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
      if(plane == 0)
      {
        return {1, 1, 1};
      }
      else if(plane == 1)
      {
        return {1, 1, 2};
      }
      else
      {
        RDCERR("Invalid plane %d in 2-plane format", plane);
        return {1, 1, 1};
      }
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R12X4_UNORM_PACK16:
      // basically just 16-bit format with only top 10-bits used
      // 10-bit and 12-bit formats are stored identically to 16-bit formats
      return {1, 1, 2};
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
      // just a 16-bit format with only top N-bits used
      // 10-bit and 12-bit formats are stored identically to 16-bit formats
      return {1, 1, 4};
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
      // just a 16-bit format with only top N-bits used
      // 10-bit and 12-bit formats are stored identically to 16-bit formats
      return {1, 1, 8};
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM:
      // 10-bit and 12-bit formats are stored identically to 16-bit formats
      // 4:2:2 packed 16-bit
      return {2, 1, 8};
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return {1, 1, 2};
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
      if(plane == 0)
      {
        return {1, 1, 2};
      }
      else if(plane == 1)
      {
        return {1, 1, 4};
      }
      else
      {
        RDCERR("Invalid plane %d in 2-plane format", plane);
        return {1, 1, 2};
      }
    default: RDCERR("Unrecognised Vulkan Format: %d", Format);
  }

  return {1, 1, 1};
}

VkExtent2D GetPlaneShape(uint32_t Width, uint32_t Height, VkFormat Format, uint32_t plane)
{
  switch(Format)
  {
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
      if(plane == 0)
        return {Width, Height};
      else
        return {RDCMAX(1U, (Width + 1) / 2), RDCMAX(1U, (Height + 1) / 2)};

    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
      if(plane == 0)
        return {Width, Height};
      else
        return {RDCMAX(1U, (Width + 1) / 2), Height};

    default: return {Width, Height};
  }
}

uint32_t GetPlaneByteSize(uint32_t Width, uint32_t Height, uint32_t Depth, VkFormat Format,
                          uint32_t mip, uint32_t plane)
{
  uint32_t mipWidth = RDCMAX(Width >> mip, 1U);
  uint32_t mipHeight = RDCMAX(Height >> mip, 1U);
  uint32_t mipDepth = RDCMAX(Depth >> mip, 1U);

  VkExtent2D planeShape = GetPlaneShape(mipWidth, mipHeight, Format, plane);

  BlockShape blockShape = GetBlockShape(Format, plane);

  uint32_t widthInBlocks = (planeShape.width + blockShape.width - 1) / blockShape.width;
  uint32_t heightInBlocks = (planeShape.height + blockShape.height - 1) / blockShape.height;

  return blockShape.bytes * widthInBlocks * heightInBlocks * mipDepth;
}

uint32_t GetByteSize(uint32_t Width, uint32_t Height, uint32_t Depth, VkFormat Format, uint32_t mip)
{
  uint32_t planeCount = GetYUVPlaneCount(Format);
  uint32_t size = 0;
  for(uint32_t p = 0; p < planeCount; p++)
    size += GetPlaneByteSize(Width, Height, Depth, Format, mip, p);
  return size;
}

ResourceFormat MakeResourceFormat(VkFormat fmt)
{
  ResourceFormat ret;

  ret.type = ResourceFormatType::Regular;
  ret.compByteWidth = 0;
  ret.compCount = 0;
  ret.compType = CompType::Typeless;

  if(fmt == VK_FORMAT_UNDEFINED)
  {
    ret.type = ResourceFormatType::Undefined;
    return ret;
  }

  switch(fmt)
  {
    case VK_FORMAT_R4G4_UNORM_PACK8: ret.type = ResourceFormatType::R4G4; break;
    case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
    case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
    case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
    case VK_FORMAT_A4B4G4R4_UNORM_PACK16: ret.type = ResourceFormatType::R4G4B4A4; break;
    case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32: ret.type = ResourceFormatType::R10G10B10A2; break;
    case VK_FORMAT_B10G11R11_UFLOAT_PACK32: ret.type = ResourceFormatType::R11G11B10; break;
    case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: ret.type = ResourceFormatType::R9G9B9E5; break;
    case VK_FORMAT_R5G6B5_UNORM_PACK16:
    case VK_FORMAT_B5G6R5_UNORM_PACK16: ret.type = ResourceFormatType::R5G6B5; break;
    case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
    case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
    case VK_FORMAT_A1R5G5B5_UNORM_PACK16: ret.type = ResourceFormatType::R5G5B5A1; break;
    case VK_FORMAT_D16_UNORM_S8_UINT: ret.type = ResourceFormatType::D16S8; break;
    case VK_FORMAT_D24_UNORM_S8_UINT: ret.type = ResourceFormatType::D24S8; break;
    case VK_FORMAT_D32_SFLOAT_S8_UINT: ret.type = ResourceFormatType::D32S8; break;
    case VK_FORMAT_S8_UINT: ret.type = ResourceFormatType::S8; break;
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: ret.type = ResourceFormatType::BC1; break;
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK: ret.type = ResourceFormatType::BC2; break;
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK: ret.type = ResourceFormatType::BC3; break;
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC4_SNORM_BLOCK: ret.type = ResourceFormatType::BC4; break;
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK: ret.type = ResourceFormatType::BC5; break;
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK: ret.type = ResourceFormatType::BC6; break;
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK: ret.type = ResourceFormatType::BC7; break;
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: ret.type = ResourceFormatType::ETC2; break;
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: ret.type = ResourceFormatType::EAC; break;
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: ret.type = ResourceFormatType::ASTC; break;
    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: ret.type = ResourceFormatType::PVRTC; break;
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: ret.type = ResourceFormatType::YUV8; break;
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
      ret.type = ResourceFormatType::YUV10;
      break;
    case VK_FORMAT_R12X4_UNORM_PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
      ret.type = ResourceFormatType::YUV12;
      break;
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: ret.type = ResourceFormatType::YUV16; break;
    default: break;
  }

  switch(fmt)
  {
    case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
    case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
    case VK_FORMAT_R5G6B5_UNORM_PACK16:
    case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
    case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_B8G8R8A8_SNORM:
    case VK_FORMAT_B8G8R8A8_USCALED:
    case VK_FORMAT_B8G8R8A8_SSCALED:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_B8G8R8A8_SRGB:
    case VK_FORMAT_B8G8R8_UNORM:
    case VK_FORMAT_B8G8R8_SNORM:
    case VK_FORMAT_B8G8R8_USCALED:
    case VK_FORMAT_B8G8R8_SSCALED:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_B8G8R8_SRGB:
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B16G16R16G16_422_UNORM: ret.SetBGRAOrder(true); break;
    default: break;
  }

  switch(fmt)
  {
    case VK_FORMAT_R8_UNORM:
    case VK_FORMAT_R8_SNORM:
    case VK_FORMAT_R8_USCALED:
    case VK_FORMAT_R8_SSCALED:
    case VK_FORMAT_R8_UINT:
    case VK_FORMAT_R8_SINT:
    case VK_FORMAT_R8_SRGB:
    case VK_FORMAT_R16_UNORM:
    case VK_FORMAT_R16_SNORM:
    case VK_FORMAT_R16_USCALED:
    case VK_FORMAT_R16_SSCALED:
    case VK_FORMAT_R16_UINT:
    case VK_FORMAT_R16_SINT:
    case VK_FORMAT_R16_SFLOAT:
    case VK_FORMAT_R32_UINT:
    case VK_FORMAT_R32_SINT:
    case VK_FORMAT_R32_SFLOAT:
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64_SFLOAT:
    case VK_FORMAT_D16_UNORM:
    case VK_FORMAT_D32_SFLOAT:
    case VK_FORMAT_X8_D24_UNORM_PACK32:
    case VK_FORMAT_S8_UINT:
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC4_SNORM_BLOCK:
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK:
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R12X4_UNORM_PACK16:
    case VK_FORMAT_A8_UNORM_KHR: ret.compCount = 1; break;
    case VK_FORMAT_R4G4_UNORM_PACK8:
    case VK_FORMAT_R8G8_UNORM:
    case VK_FORMAT_R8G8_SNORM:
    case VK_FORMAT_R8G8_USCALED:
    case VK_FORMAT_R8G8_SSCALED:
    case VK_FORMAT_R8G8_UINT:
    case VK_FORMAT_R8G8_SINT:
    case VK_FORMAT_R8G8_SRGB:
    case VK_FORMAT_R16G16_UNORM:
    case VK_FORMAT_R16G16_SNORM:
    case VK_FORMAT_R16G16_USCALED:
    case VK_FORMAT_R16G16_SSCALED:
    case VK_FORMAT_R16G16_UINT:
    case VK_FORMAT_R16G16_SINT:
    case VK_FORMAT_R16G16_SFLOAT:
    case VK_FORMAT_R32G32_UINT:
    case VK_FORMAT_R32G32_SINT:
    case VK_FORMAT_R32G32_SFLOAT:
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64_SFLOAT:
    case VK_FORMAT_D16_UNORM_S8_UINT:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT_S8_UINT:
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
    case VK_FORMAT_R16G16_S10_5_NV: ret.compCount = 2; break;
    case VK_FORMAT_R5G6B5_UNORM_PACK16:
    case VK_FORMAT_R8G8B8_UNORM:
    case VK_FORMAT_R8G8B8_SNORM:
    case VK_FORMAT_R8G8B8_USCALED:
    case VK_FORMAT_R8G8B8_SSCALED:
    case VK_FORMAT_R8G8B8_UINT:
    case VK_FORMAT_R8G8B8_SINT:
    case VK_FORMAT_R8G8B8_SRGB:
    case VK_FORMAT_R16G16B16_UNORM:
    case VK_FORMAT_R16G16B16_SNORM:
    case VK_FORMAT_R16G16B16_USCALED:
    case VK_FORMAT_R16G16B16_SSCALED:
    case VK_FORMAT_R16G16B16_UINT:
    case VK_FORMAT_R16G16B16_SINT:
    case VK_FORMAT_R16G16B16_SFLOAT:
    case VK_FORMAT_R32G32B32_UINT:
    case VK_FORMAT_R32G32B32_SINT:
    case VK_FORMAT_R32G32B32_SFLOAT:
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64_SFLOAT:
    case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
    case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_B5G6R5_UNORM_PACK16:
    case VK_FORMAT_B8G8R8_UNORM:
    case VK_FORMAT_B8G8R8_SNORM:
    case VK_FORMAT_B8G8R8_USCALED:
    case VK_FORMAT_B8G8R8_SSCALED:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_B8G8R8_SRGB:
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: ret.compCount = 3; break;
    case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
    case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
    case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
    case VK_FORMAT_R8G8B8A8_UNORM:
    case VK_FORMAT_R8G8B8A8_SNORM:
    case VK_FORMAT_R8G8B8A8_USCALED:
    case VK_FORMAT_R8G8B8A8_SSCALED:
    case VK_FORMAT_R8G8B8A8_UINT:
    case VK_FORMAT_R8G8B8A8_SINT:
    case VK_FORMAT_R8G8B8A8_SRGB:
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    case VK_FORMAT_R16G16B16A16_UNORM:
    case VK_FORMAT_R16G16B16A16_SNORM:
    case VK_FORMAT_R16G16B16A16_USCALED:
    case VK_FORMAT_R16G16B16A16_SSCALED:
    case VK_FORMAT_R16G16B16A16_UINT:
    case VK_FORMAT_R16G16B16A16_SINT:
    case VK_FORMAT_R16G16B16A16_SFLOAT:
    case VK_FORMAT_R32G32B32A32_UINT:
    case VK_FORMAT_R32G32B32A32_SINT:
    case VK_FORMAT_R32G32B32A32_SFLOAT:
    case VK_FORMAT_R64G64B64A64_UINT:
    case VK_FORMAT_R64G64B64A64_SINT:
    case VK_FORMAT_R64G64B64A64_SFLOAT:
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
    case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
    case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
    case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_B8G8R8A8_SNORM:
    case VK_FORMAT_B8G8R8A8_USCALED:
    case VK_FORMAT_B8G8R8A8_SSCALED:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_B8G8R8A8_SRGB:
    case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
    case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
    case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: ret.compCount = 4; break;
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: ret.compCount = 4; break;
    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: ret.compCount = 4; break;
    case VK_FORMAT_UNDEFINED:
    case VK_FORMAT_MAX_ENUM: ret.compCount = 1; break;
  }

  switch(fmt)
  {
    case VK_FORMAT_R4G4_UNORM_PACK8:
    case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
    case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
    case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
    case VK_FORMAT_R5G6B5_UNORM_PACK16:
    case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
    case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
    case VK_FORMAT_A8_UNORM_KHR:
    case VK_FORMAT_R8_UNORM:
    case VK_FORMAT_R8G8_UNORM:
    case VK_FORMAT_R8G8B8_UNORM:
    case VK_FORMAT_R8G8B8A8_UNORM:
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_R16_UNORM:
    case VK_FORMAT_R16G16_UNORM:
    case VK_FORMAT_R16G16B16_UNORM:
    case VK_FORMAT_R16G16B16A16_UNORM:
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
    case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
    case VK_FORMAT_B5G6R5_UNORM_PACK16:
    case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
    case VK_FORMAT_B8G8R8_UNORM:
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: ret.compType = CompType::UNorm; break;
    case VK_FORMAT_R8_SRGB:
    case VK_FORMAT_R8G8_SRGB:
    case VK_FORMAT_R8G8B8_SRGB:
    case VK_FORMAT_R8G8B8A8_SRGB:
    case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_B8G8R8_SRGB:
    case VK_FORMAT_B8G8R8A8_SRGB:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: ret.compType = CompType::UNormSRGB; break;
    case VK_FORMAT_R8_SNORM:
    case VK_FORMAT_R8G8_SNORM:
    case VK_FORMAT_R8G8B8_SNORM:
    case VK_FORMAT_R8G8B8A8_SNORM:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_R16_SNORM:
    case VK_FORMAT_R16G16_SNORM:
    case VK_FORMAT_R16G16B16_SNORM:
    case VK_FORMAT_R16G16B16A16_SNORM:
    case VK_FORMAT_BC4_SNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
    case VK_FORMAT_B8G8R8_SNORM:
    case VK_FORMAT_B8G8R8A8_SNORM:
    case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_SNORM_PACK32: ret.compType = CompType::SNorm; break;
    case VK_FORMAT_R8_USCALED:
    case VK_FORMAT_R8G8_USCALED:
    case VK_FORMAT_R8G8B8_USCALED:
    case VK_FORMAT_R8G8B8A8_USCALED:
    case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
    case VK_FORMAT_R16_USCALED:
    case VK_FORMAT_R16G16_USCALED:
    case VK_FORMAT_R16G16B16_USCALED:
    case VK_FORMAT_R16G16B16A16_USCALED:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_B8G8R8_USCALED:
    case VK_FORMAT_B8G8R8A8_USCALED:
    case VK_FORMAT_A2B10G10R10_USCALED_PACK32: ret.compType = CompType::UScaled; break;
    case VK_FORMAT_R8_SSCALED:
    case VK_FORMAT_R8G8_SSCALED:
    case VK_FORMAT_R8G8B8_SSCALED:
    case VK_FORMAT_R8G8B8A8_SSCALED:
    case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_R16_SSCALED:
    case VK_FORMAT_R16G16_SSCALED:
    case VK_FORMAT_R16G16B16_SSCALED:
    case VK_FORMAT_R16G16B16A16_SSCALED:
    case VK_FORMAT_B8G8R8_SSCALED:
    case VK_FORMAT_B8G8R8A8_SSCALED:
    case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: ret.compType = CompType::SScaled; break;
    case VK_FORMAT_R8_UINT:
    case VK_FORMAT_R8G8_UINT:
    case VK_FORMAT_R8G8B8_UINT:
    case VK_FORMAT_R8G8B8A8_UINT:
    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_R16_UINT:
    case VK_FORMAT_R16G16_UINT:
    case VK_FORMAT_R16G16B16_UINT:
    case VK_FORMAT_R16G16B16A16_UINT:
    case VK_FORMAT_R32_UINT:
    case VK_FORMAT_R32G32_UINT:
    case VK_FORMAT_R32G32B32_UINT:
    case VK_FORMAT_R32G32B32A32_UINT:
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64A64_UINT:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32: ret.compType = CompType::UInt; break;
    case VK_FORMAT_R8_SINT:
    case VK_FORMAT_R8G8_SINT:
    case VK_FORMAT_R8G8B8_SINT:
    case VK_FORMAT_R8G8B8A8_SINT:
    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    case VK_FORMAT_R16_SINT:
    case VK_FORMAT_R16G16_SINT:
    case VK_FORMAT_R16G16B16_SINT:
    case VK_FORMAT_R16G16B16A16_SINT:
    case VK_FORMAT_R32_SINT:
    case VK_FORMAT_R32G32_SINT:
    case VK_FORMAT_R32G32B32_SINT:
    case VK_FORMAT_R32G32B32A32_SINT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64A64_SINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32: ret.compType = CompType::SInt; break;
    case VK_FORMAT_R16_SFLOAT:
    case VK_FORMAT_R16G16_SFLOAT:
    case VK_FORMAT_R16G16B16_SFLOAT:
    case VK_FORMAT_R16G16B16A16_SFLOAT:
    case VK_FORMAT_R32_SFLOAT:
    case VK_FORMAT_R32G32_SFLOAT:
    case VK_FORMAT_R32G32B32_SFLOAT:
    case VK_FORMAT_R32G32B32A32_SFLOAT:
    case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
    case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
    case VK_FORMAT_R16G16_S10_5_NV:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
    case VK_FORMAT_R64_SFLOAT:
    case VK_FORMAT_R64G64_SFLOAT:
    case VK_FORMAT_R64G64B64_SFLOAT:
    case VK_FORMAT_R64G64B64A64_SFLOAT: ret.compType = CompType::Float; break;
    case VK_FORMAT_S8_UINT:
    case VK_FORMAT_D16_UNORM:
    case VK_FORMAT_X8_D24_UNORM_PACK32:
    case VK_FORMAT_D32_SFLOAT:
    case VK_FORMAT_D16_UNORM_S8_UINT:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT_S8_UINT: ret.compType = CompType::Depth; break;
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_R12X4_UNORM_PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: ret.compType = CompType::UNorm; break;
    case VK_FORMAT_UNDEFINED:
    case VK_FORMAT_MAX_ENUM: ret.compType = CompType::Typeless; break;
  }

  switch(fmt)
  {
    case VK_FORMAT_R8_UNORM:
    case VK_FORMAT_R8_SNORM:
    case VK_FORMAT_R8_USCALED:
    case VK_FORMAT_R8_SSCALED:
    case VK_FORMAT_R8_UINT:
    case VK_FORMAT_R8_SINT:
    case VK_FORMAT_R8_SRGB:
    case VK_FORMAT_R8G8_UNORM:
    case VK_FORMAT_R8G8_SNORM:
    case VK_FORMAT_R8G8_USCALED:
    case VK_FORMAT_R8G8_SSCALED:
    case VK_FORMAT_R8G8_UINT:
    case VK_FORMAT_R8G8_SINT:
    case VK_FORMAT_R8G8_SRGB:
    case VK_FORMAT_R8G8B8_UNORM:
    case VK_FORMAT_R8G8B8_SNORM:
    case VK_FORMAT_R8G8B8_USCALED:
    case VK_FORMAT_R8G8B8_SSCALED:
    case VK_FORMAT_R8G8B8_UINT:
    case VK_FORMAT_R8G8B8_SINT:
    case VK_FORMAT_R8G8B8_SRGB:
    case VK_FORMAT_R8G8B8A8_UNORM:
    case VK_FORMAT_R8G8B8A8_SNORM:
    case VK_FORMAT_R8G8B8A8_USCALED:
    case VK_FORMAT_R8G8B8A8_SSCALED:
    case VK_FORMAT_R8G8B8A8_UINT:
    case VK_FORMAT_R8G8B8A8_SINT:
    case VK_FORMAT_R8G8B8A8_SRGB:
    case VK_FORMAT_S8_UINT:
    case VK_FORMAT_B8G8R8_UNORM:
    case VK_FORMAT_B8G8R8_SNORM:
    case VK_FORMAT_B8G8R8_USCALED:
    case VK_FORMAT_B8G8R8_SSCALED:
    case VK_FORMAT_B8G8R8_UINT:
    case VK_FORMAT_B8G8R8_SINT:
    case VK_FORMAT_B8G8R8_SRGB:
    case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
    case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
    case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_B8G8R8A8_SNORM:
    case VK_FORMAT_B8G8R8A8_USCALED:
    case VK_FORMAT_B8G8R8A8_SSCALED:
    case VK_FORMAT_B8G8R8A8_UINT:
    case VK_FORMAT_B8G8R8A8_SINT:
    case VK_FORMAT_B8G8R8A8_SRGB:
    case VK_FORMAT_A8_UNORM_KHR: ret.compByteWidth = 1; break;
    case VK_FORMAT_R16_UNORM:
    case VK_FORMAT_R16_SNORM:
    case VK_FORMAT_R16_USCALED:
    case VK_FORMAT_R16_SSCALED:
    case VK_FORMAT_R16_UINT:
    case VK_FORMAT_R16_SINT:
    case VK_FORMAT_R16_SFLOAT:
    case VK_FORMAT_R16G16_UNORM:
    case VK_FORMAT_R16G16_SNORM:
    case VK_FORMAT_R16G16_USCALED:
    case VK_FORMAT_R16G16_SSCALED:
    case VK_FORMAT_R16G16_UINT:
    case VK_FORMAT_R16G16_SINT:
    case VK_FORMAT_R16G16_SFLOAT:
    case VK_FORMAT_R16G16B16_UNORM:
    case VK_FORMAT_R16G16B16_SNORM:
    case VK_FORMAT_R16G16B16_USCALED:
    case VK_FORMAT_R16G16B16_SSCALED:
    case VK_FORMAT_R16G16B16_UINT:
    case VK_FORMAT_R16G16B16_SINT:
    case VK_FORMAT_R16G16B16_SFLOAT:
    case VK_FORMAT_R16G16B16A16_UNORM:
    case VK_FORMAT_R16G16B16A16_SNORM:
    case VK_FORMAT_R16G16B16A16_USCALED:
    case VK_FORMAT_R16G16B16A16_SSCALED:
    case VK_FORMAT_R16G16B16A16_UINT:
    case VK_FORMAT_R16G16B16A16_SINT:
    case VK_FORMAT_R16G16B16A16_SFLOAT:
    case VK_FORMAT_D16_UNORM: ret.compByteWidth = 2; break;
    case VK_FORMAT_X8_D24_UNORM_PACK32: ret.compByteWidth = 3; break;
    case VK_FORMAT_R32_UINT:
    case VK_FORMAT_R32_SINT:
    case VK_FORMAT_R32_SFLOAT:
    case VK_FORMAT_R32G32_UINT:
    case VK_FORMAT_R32G32_SINT:
    case VK_FORMAT_R32G32_SFLOAT:
    case VK_FORMAT_R32G32B32_UINT:
    case VK_FORMAT_R32G32B32_SINT:
    case VK_FORMAT_R32G32B32_SFLOAT:
    case VK_FORMAT_R32G32B32A32_UINT:
    case VK_FORMAT_R32G32B32A32_SINT:
    case VK_FORMAT_R32G32B32A32_SFLOAT:
    case VK_FORMAT_D32_SFLOAT: ret.compByteWidth = 4; break;
    case VK_FORMAT_R64_UINT:
    case VK_FORMAT_R64G64_UINT:
    case VK_FORMAT_R64G64B64_UINT:
    case VK_FORMAT_R64G64B64A64_UINT:
    case VK_FORMAT_R64_SINT:
    case VK_FORMAT_R64G64_SINT:
    case VK_FORMAT_R64G64B64_SINT:
    case VK_FORMAT_R64G64B64A64_SINT:
    case VK_FORMAT_R64_SFLOAT:
    case VK_FORMAT_R64G64_SFLOAT:
    case VK_FORMAT_R64G64B64_SFLOAT:
    case VK_FORMAT_R64G64B64A64_SFLOAT: ret.compByteWidth = 8; break;
    case VK_FORMAT_R4G4_UNORM_PACK8:
    case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
    case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
    case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
    case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
    case VK_FORMAT_R5G6B5_UNORM_PACK16:
    case VK_FORMAT_B5G6R5_UNORM_PACK16:
    case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
    case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
    case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
    case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
    case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
    case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
    case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
    case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
    case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
    case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
    case VK_FORMAT_D16_UNORM_S8_UINT:
    case VK_FORMAT_D24_UNORM_S8_UINT:
    case VK_FORMAT_D32_SFLOAT_S8_UINT:
    case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
    case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
    case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
    case VK_FORMAT_BC2_UNORM_BLOCK:
    case VK_FORMAT_BC2_SRGB_BLOCK:
    case VK_FORMAT_BC3_UNORM_BLOCK:
    case VK_FORMAT_BC3_SRGB_BLOCK:
    case VK_FORMAT_BC4_UNORM_BLOCK:
    case VK_FORMAT_BC4_SNORM_BLOCK:
    case VK_FORMAT_BC5_UNORM_BLOCK:
    case VK_FORMAT_BC5_SNORM_BLOCK:
    case VK_FORMAT_BC6H_UFLOAT_BLOCK:
    case VK_FORMAT_BC6H_SFLOAT_BLOCK:
    case VK_FORMAT_BC7_UNORM_BLOCK:
    case VK_FORMAT_BC7_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
    case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
    case VK_FORMAT_EAC_R11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11_SNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
    case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
    case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
    case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
    case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
    case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
    case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
    case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
    case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
    case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: ret.compByteWidth = 1; break;
    case VK_FORMAT_G8B8G8R8_422_UNORM:
    case VK_FORMAT_B8G8R8G8_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
    case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
    case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: ret.compByteWidth = 1; break;
    case VK_FORMAT_R10X6_UNORM_PACK16:
    case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
    case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
    case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
    case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_R12X4_UNORM_PACK16:
    case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
    case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
    case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
    case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
    case VK_FORMAT_G16B16G16R16_422_UNORM:
    case VK_FORMAT_B16G16R16G16_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
    case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
    case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
    case VK_FORMAT_R16G16_S10_5_NV: ret.compByteWidth = 2; break;
    case VK_FORMAT_UNDEFINED:
    case VK_FORMAT_MAX_ENUM: ret.compByteWidth = 1; break;
  }

  if(IsYUVFormat(fmt))
  {
    ret.SetYUVPlaneCount(GetYUVPlaneCount(fmt));

    switch(fmt)
    {
      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: ret.SetYUVSubsampling(420); break;
      case VK_FORMAT_G8B8G8R8_422_UNORM:
      case VK_FORMAT_B8G8R8G8_422_UNORM:
      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
      case VK_FORMAT_G16B16G16R16_422_UNORM:
      case VK_FORMAT_B16G16R16G16_422_UNORM:
      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: ret.SetYUVSubsampling(422); break;
      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
      case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
      case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
      case VK_FORMAT_R10X6_UNORM_PACK16:
      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
      case VK_FORMAT_R12X4_UNORM_PACK16:
      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: ret.SetYUVSubsampling(444); break;
      default: break;
    }
  }

  return ret;
}

VkFormat MakeVkFormat(ResourceFormat fmt)
{
  VkFormat ret = VK_FORMAT_UNDEFINED;

  if(fmt.Special())
  {
    switch(fmt.type)
    {
      case ResourceFormatType::Undefined: return ret;
      case ResourceFormatType::BC1:
      {
        if(fmt.compCount == 3)
          ret = fmt.SRGBCorrected() ? VK_FORMAT_BC1_RGB_SRGB_BLOCK : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
        else
          ret = fmt.SRGBCorrected() ? VK_FORMAT_BC1_RGBA_SRGB_BLOCK : VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
        break;
      }
      case ResourceFormatType::BC2:
        ret = fmt.SRGBCorrected() ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK;
        break;
      case ResourceFormatType::BC3:
        ret = fmt.SRGBCorrected() ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
        break;
      case ResourceFormatType::BC4:
        ret = fmt.compType == CompType::SNorm ? VK_FORMAT_BC4_SNORM_BLOCK : VK_FORMAT_BC4_UNORM_BLOCK;
        break;
      case ResourceFormatType::BC5:
        ret = fmt.compType == CompType::SNorm ? VK_FORMAT_BC5_SNORM_BLOCK : VK_FORMAT_BC5_UNORM_BLOCK;
        break;
      case ResourceFormatType::BC6:
        ret = fmt.compType == CompType::SNorm ? VK_FORMAT_BC6H_SFLOAT_BLOCK
                                              : VK_FORMAT_BC6H_UFLOAT_BLOCK;
        break;
      case ResourceFormatType::BC7:
        ret = fmt.SRGBCorrected() ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
        break;
      case ResourceFormatType::ETC2:
      {
        if(fmt.compCount == 3)
          ret = fmt.SRGBCorrected() ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK
                                    : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
        else
          ret = fmt.SRGBCorrected() ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK
                                    : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
        break;
      }
      case ResourceFormatType::EAC:
      {
        if(fmt.compCount == 1)
          ret = fmt.compType == CompType::SNorm ? VK_FORMAT_EAC_R11_SNORM_BLOCK
                                                : VK_FORMAT_EAC_R11_UNORM_BLOCK;
        else if(fmt.compCount == 2)
          ret = fmt.compType == CompType::SNorm ? VK_FORMAT_EAC_R11G11_SNORM_BLOCK
                                                : VK_FORMAT_EAC_R11G11_UNORM_BLOCK;
        else
          ret = fmt.SRGBCorrected() ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK
                                    : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
        break;
      }
      case ResourceFormatType::R10G10B10A2:
        if(fmt.compType == CompType::UNorm)
          ret = fmt.BGRAOrder() ? VK_FORMAT_A2R10G10B10_UNORM_PACK32
                                : VK_FORMAT_A2B10G10R10_UNORM_PACK32;
        else if(fmt.compType == CompType::UInt)
          ret = fmt.BGRAOrder() ? VK_FORMAT_A2R10G10B10_UINT_PACK32
                                : VK_FORMAT_A2B10G10R10_UINT_PACK32;
        else if(fmt.compType == CompType::UScaled)
          ret = fmt.BGRAOrder() ? VK_FORMAT_A2R10G10B10_USCALED_PACK32
                                : VK_FORMAT_A2B10G10R10_USCALED_PACK32;
        else if(fmt.compType == CompType::SNorm)
          ret = fmt.BGRAOrder() ? VK_FORMAT_A2R10G10B10_SNORM_PACK32
                                : VK_FORMAT_A2B10G10R10_SNORM_PACK32;
        else if(fmt.compType == CompType::SInt)
          ret = fmt.BGRAOrder() ? VK_FORMAT_A2R10G10B10_SINT_PACK32
                                : VK_FORMAT_A2B10G10R10_SINT_PACK32;
        else if(fmt.compType == CompType::SScaled)
          ret = fmt.BGRAOrder() ? VK_FORMAT_A2R10G10B10_SSCALED_PACK32
                                : VK_FORMAT_A2B10G10R10_SSCALED_PACK32;
        break;
      case ResourceFormatType::R11G11B10: ret = VK_FORMAT_B10G11R11_UFLOAT_PACK32; break;
      case ResourceFormatType::R5G6B5:
        ret = fmt.BGRAOrder() ? VK_FORMAT_R5G6B5_UNORM_PACK16 : VK_FORMAT_B5G6R5_UNORM_PACK16;
        break;
      case ResourceFormatType::R5G5B5A1:
        ret = fmt.BGRAOrder() ? VK_FORMAT_R5G5B5A1_UNORM_PACK16 : VK_FORMAT_B5G5R5A1_UNORM_PACK16;
        break;
      case ResourceFormatType::R9G9B9E5: ret = VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; break;
      case ResourceFormatType::R4G4B4A4:
        ret = fmt.BGRAOrder() ? VK_FORMAT_R4G4B4A4_UNORM_PACK16 : VK_FORMAT_B4G4R4A4_UNORM_PACK16;
        break;
      case ResourceFormatType::R4G4: ret = VK_FORMAT_R4G4_UNORM_PACK8; break;
      case ResourceFormatType::D16S8: ret = VK_FORMAT_D16_UNORM_S8_UINT; break;
      case ResourceFormatType::D24S8: ret = VK_FORMAT_D24_UNORM_S8_UINT; break;
      case ResourceFormatType::D32S8: ret = VK_FORMAT_D32_SFLOAT_S8_UINT; break;
      case ResourceFormatType::S8: ret = VK_FORMAT_S8_UINT; break;
      case ResourceFormatType::YUV8:
      {
        int subsampling = fmt.YUVSubsampling();
        int planeCount = fmt.YUVPlaneCount();

        // don't support anything but 3 components
        if(fmt.compCount != 3)
          return VK_FORMAT_UNDEFINED;

        if(subsampling == 444)
        {
          if(planeCount == 3)
            return VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM;
          else if(planeCount == 2)
            return VK_FORMAT_G8_B8R8_2PLANE_444_UNORM;

          return VK_FORMAT_UNDEFINED;
        }
        else if(subsampling == 422)
        {
          if(planeCount == 1)
            return fmt.BGRAOrder() ? VK_FORMAT_B8G8R8G8_422_UNORM : VK_FORMAT_G8B8G8R8_422_UNORM;
          else if(planeCount == 2)
            return VK_FORMAT_G8_B8R8_2PLANE_422_UNORM;
          else if(planeCount == 3)
            return VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM;
        }
        else if(subsampling == 420)
        {
          if(planeCount == 2)
            return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
          else if(planeCount == 3)
            return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
          else
            return VK_FORMAT_UNDEFINED;
        }

        return VK_FORMAT_UNDEFINED;
      }
      case ResourceFormatType::YUV10:
      {
        int subsampling = fmt.YUVSubsampling();
        int planeCount = fmt.YUVPlaneCount();

        if(fmt.compCount == 1)
        {
          if(subsampling == 444 && planeCount == 1)
            return VK_FORMAT_R10X6_UNORM_PACK16;
          return VK_FORMAT_UNDEFINED;
        }
        else if(fmt.compCount == 2)
        {
          if(subsampling == 444 && planeCount == 1)
            return VK_FORMAT_R10X6G10X6_UNORM_2PACK16;
          return VK_FORMAT_UNDEFINED;
        }
        else if(fmt.compCount == 4)
        {
          if(subsampling == 444 && planeCount == 1)
            return VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16;
          return VK_FORMAT_UNDEFINED;
        }

        if(subsampling == 444)
        {
          if(planeCount == 3)
            return VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16;
          else if(planeCount == 2)
            return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16;
          return VK_FORMAT_UNDEFINED;
        }
        else if(subsampling == 422)
        {
          if(planeCount == 1)
            return fmt.BGRAOrder() ? VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16
                                   : VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16;
          else if(planeCount == 2)
            return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16;
          else if(planeCount == 3)
            return VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16;
        }
        else if(subsampling == 420)
        {
          if(planeCount == 2)
            return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16;
          else if(planeCount == 3)
            return VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16;
          else
            return VK_FORMAT_UNDEFINED;
        }

        return VK_FORMAT_UNDEFINED;
      }
      case ResourceFormatType::YUV12:
      {
        int subsampling = fmt.YUVSubsampling();
        int planeCount = fmt.YUVPlaneCount();

        if(fmt.compCount == 1)
        {
          if(subsampling == 444 && planeCount == 1)
            return VK_FORMAT_R12X4_UNORM_PACK16;
          return VK_FORMAT_UNDEFINED;
        }
        else if(fmt.compCount == 2)
        {
          if(subsampling == 444 && planeCount == 1)
            return VK_FORMAT_R12X4G12X4_UNORM_2PACK16;
          return VK_FORMAT_UNDEFINED;
        }
        else if(fmt.compCount == 4)
        {
          if(subsampling == 444 && planeCount == 1)
            return VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16;
          return VK_FORMAT_UNDEFINED;
        }

        if(subsampling == 444)
        {
          if(planeCount == 3)
            return VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16;
          else if(planeCount == 2)
            return VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16;
          return VK_FORMAT_UNDEFINED;
        }
        else if(subsampling == 422)
        {
          if(planeCount == 1)
            return fmt.BGRAOrder() ? VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16
                                   : VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16;
          else if(planeCount == 2)
            return VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16;
          else if(planeCount == 3)
            return VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16;
        }
        else if(subsampling == 420)
        {
          if(planeCount == 2)
            return VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16;
          else if(planeCount == 3)
            return VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16;
          else
            return VK_FORMAT_UNDEFINED;
        }

        return VK_FORMAT_UNDEFINED;
      }
      case ResourceFormatType::YUV16:
      {
        int subsampling = fmt.YUVSubsampling();
        int planeCount = fmt.YUVPlaneCount();

        if(subsampling == 444)
        {
          if(planeCount == 3)
            return VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
          else if(planeCount == 2)
            return VK_FORMAT_G16_B16R16_2PLANE_444_UNORM;
          return VK_FORMAT_UNDEFINED;
        }
        else if(subsampling == 422)
        {
          if(planeCount == 1)
            return fmt.BGRAOrder() ? VK_FORMAT_B16G16R16G16_422_UNORM
                                   : VK_FORMAT_G16B16G16R16_422_UNORM;
          else if(planeCount == 2)
            return VK_FORMAT_G16_B16R16_2PLANE_422_UNORM;
          else if(planeCount == 3)
            return VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM;
        }
        else if(subsampling == 420)
        {
          if(planeCount == 2)
            return VK_FORMAT_G16_B16R16_2PLANE_420_UNORM;
          else if(planeCount == 3)
            return VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM;
          else
            return VK_FORMAT_UNDEFINED;
        }

        return VK_FORMAT_UNDEFINED;
      }
      default: RDCERR("Unsupported resource format type %u", fmt.type); break;
    }
  }
  else if(fmt.compCount == 4)
  {
    if(fmt.SRGBCorrected())
    {
      ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_R8G8B8A8_SRGB;
    }
    else if(fmt.compByteWidth == 8)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R64G64B64A64_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R64G64B64A64_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R64G64B64A64_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 4)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R32G32B32A32_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R32G32B32A32_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R32G32B32A32_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 2)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R16G16B16A16_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R16G16B16A16_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R16G16B16A16_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = VK_FORMAT_R16G16B16A16_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = VK_FORMAT_R16G16B16A16_UNORM;
      else if(fmt.compType == CompType::SScaled)
        ret = VK_FORMAT_R16G16B16A16_SSCALED;
      else if(fmt.compType == CompType::UScaled)
        ret = VK_FORMAT_R16G16B16A16_USCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 1)
    {
      if(fmt.compType == CompType::SInt)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_SINT : VK_FORMAT_R8G8B8A8_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_UINT : VK_FORMAT_R8G8B8A8_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_SNORM : VK_FORMAT_R8G8B8A8_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8G8B8A8_UNORM;
      else if(fmt.compType == CompType::SScaled)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_SSCALED : VK_FORMAT_R8G8B8A8_SSCALED;
      else if(fmt.compType == CompType::UScaled)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8A8_USCALED : VK_FORMAT_R8G8B8A8_USCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else
    {
      RDCERR("Unrecognised 4-component byte width: %d", fmt.compByteWidth);
    }
  }
  else if(fmt.compCount == 3)
  {
    if(fmt.SRGBCorrected())
    {
      ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_SRGB : VK_FORMAT_R8G8B8_SRGB;
    }
    else if(fmt.compByteWidth == 8)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R64G64B64_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R64G64B64_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R64G64B64_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 4)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R32G32B32_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R32G32B32_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R32G32B32_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 2)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R16G16B16_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R16G16B16_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R16G16B16_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = VK_FORMAT_R16G16B16_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = VK_FORMAT_R16G16B16_UNORM;
      else if(fmt.compType == CompType::SScaled)
        ret = VK_FORMAT_R16G16B16_SSCALED;
      else if(fmt.compType == CompType::UScaled)
        ret = VK_FORMAT_R16G16B16_USCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 1)
    {
      if(fmt.compType == CompType::SInt)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_SINT : VK_FORMAT_R8G8B8_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_UINT : VK_FORMAT_R8G8B8_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_SNORM : VK_FORMAT_R8G8B8_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_UNORM : VK_FORMAT_R8G8B8_UNORM;
      else if(fmt.compType == CompType::SScaled)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_SSCALED : VK_FORMAT_R8G8B8_SSCALED;
      else if(fmt.compType == CompType::UScaled)
        ret = fmt.BGRAOrder() ? VK_FORMAT_B8G8R8_USCALED : VK_FORMAT_R8G8B8_USCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else
    {
      RDCERR("Unrecognised 3-component byte width: %d", fmt.compByteWidth);
    }
  }
  else if(fmt.compCount == 2)
  {
    if(fmt.SRGBCorrected())
    {
      ret = VK_FORMAT_R8G8_SRGB;
    }
    else if(fmt.compByteWidth == 8)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R64G64_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R64G64_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R64G64_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 4)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R32G32_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R32G32_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R32G32_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 2)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R16G16_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R16G16_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R16G16_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = VK_FORMAT_R16G16_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = VK_FORMAT_R16G16_UNORM;
      else if(fmt.compType == CompType::SScaled)
        ret = VK_FORMAT_R16G16_SSCALED;
      else if(fmt.compType == CompType::UScaled)
        ret = VK_FORMAT_R16G16_USCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 1)
    {
      if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R8G8_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R8G8_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = VK_FORMAT_R8G8_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = VK_FORMAT_R8G8_UNORM;
      else if(fmt.compType == CompType::SScaled)
        ret = VK_FORMAT_R8G8_SSCALED;
      else if(fmt.compType == CompType::UScaled)
        ret = VK_FORMAT_R8G8_USCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else
    {
      RDCERR("Unrecognised 2-component byte width: %d", fmt.compByteWidth);
    }
  }
  else if(fmt.compCount == 1)
  {
    if(fmt.SRGBCorrected())
    {
      ret = VK_FORMAT_R8_SRGB;
    }
    else if(fmt.compByteWidth == 8)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R64_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R64_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R64_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 4)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R32_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R32_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R32_UINT;
      else if(fmt.compType == CompType::Depth)
        ret = VK_FORMAT_D32_SFLOAT;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 3)
    {
      if(fmt.compType == CompType::Depth)
        ret = VK_FORMAT_X8_D24_UNORM_PACK32;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 2)
    {
      if(fmt.compType == CompType::Float)
        ret = VK_FORMAT_R16_SFLOAT;
      else if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R16_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R16_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = VK_FORMAT_R16_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = VK_FORMAT_R16_UNORM;
      else if(fmt.compType == CompType::Depth)
        ret = VK_FORMAT_D16_UNORM;
      else if(fmt.compType == CompType::UScaled)
        ret = VK_FORMAT_R16_USCALED;
      else if(fmt.compType == CompType::SScaled)
        ret = VK_FORMAT_R16_SSCALED;
      else
        RDCERR("Unrecognised component type");
    }
    else if(fmt.compByteWidth == 1)
    {
      if(fmt.compType == CompType::SInt)
        ret = VK_FORMAT_R8_SINT;
      else if(fmt.compType == CompType::UInt)
        ret = VK_FORMAT_R8_UINT;
      else if(fmt.compType == CompType::SNorm)
        ret = VK_FORMAT_R8_SNORM;
      else if(fmt.compType == CompType::UNorm)
        ret = VK_FORMAT_R8_UNORM;
      else if(fmt.compType == CompType::UScaled)
        ret = VK_FORMAT_R8_USCALED;
      else if(fmt.compType == CompType::SScaled)
        ret = VK_FORMAT_R8_SSCALED;
      else if(fmt.compType == CompType::Depth)
        ret = VK_FORMAT_S8_UINT;
      else
        RDCERR("Unrecognised component type");
    }
    else
    {
      RDCERR("Unrecognised 1-component byte width: %d", fmt.compByteWidth);
    }
  }
  else
  {
    RDCERR("Unrecognised component count: %d", fmt.compCount);
  }

  if(ret == VK_FORMAT_UNDEFINED)
    RDCERR("No known vulkan format corresponding to resource format!");

  return ret;
}

VkImageAspectFlags FormatImageAspects(VkFormat fmt)
{
  if(IsStencilOnlyFormat(fmt))
    return VK_IMAGE_ASPECT_STENCIL_BIT;
  else if(IsDepthOnlyFormat(fmt))
    return VK_IMAGE_ASPECT_DEPTH_BIT;
  else if(IsDepthAndStencilFormat(fmt))
    return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
  else if(GetYUVPlaneCount(fmt) == 3)
    return VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT;
  else if(GetYUVPlaneCount(fmt) == 2)
    return VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
  else
    return VK_IMAGE_ASPECT_COLOR_BIT;
}

RenderPassInfo::RenderPassInfo(const VkRenderPassCreateInfo &ci)
{
  // *2 in case we need separate barriers for depth and stencil, +1 for the terminating null
  // attachment info (though separate depth/stencil buffers aren't needed here, we keep the
  // array size the same)
  uint32_t arrayCount = ci.attachmentCount * 2 + 1;
  imageAttachments = new AttachmentInfo[arrayCount];
  RDCEraseMem(imageAttachments, arrayCount * sizeof(imageAttachments[0]));

  for(uint32_t i = 0; i < ci.attachmentCount; ++i)
  {
    imageAttachments[i].record = NULL;
    imageAttachments[i].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
    imageAttachments[i].barrier.oldLayout = ci.pAttachments[i].initialLayout;
    imageAttachments[i].barrier.newLayout = ci.pAttachments[i].finalLayout;
    imageAttachments[i].barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    imageAttachments[i].barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    imageAttachments[i].format = ci.pAttachments[i].format;
    imageAttachments[i].samples = ci.pAttachments[i].samples;
  }

  // VK_KHR_multiview
  const VkRenderPassMultiviewCreateInfo *multiview =
      (const VkRenderPassMultiviewCreateInfo *)FindNextStruct(
          &ci, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO);

  if(multiview && multiview->subpassCount > 0)
  {
    multiviewViewMaskTable = new uint32_t[arrayCount];
    RDCEraseMem(multiviewViewMaskTable, arrayCount * sizeof(multiviewViewMaskTable[0]));
  }
  else
  {
    multiviewViewMaskTable = NULL;
  }

  loadOpTable = new VkAttachmentLoadOp[arrayCount];
  storeOpTable = new VkAttachmentStoreOp[arrayCount];

  // we only care about which attachment doesn't have LOAD specificed, so we
  // assume all attachments have VK_ATTACHMENT_LOAD_OP_LOAD until proven otherwise.
  // similarly for store
  for(uint32_t a = 0; a < arrayCount; ++a)
  {
    loadOpTable[a] = VK_ATTACHMENT_LOAD_OP_LOAD;
    storeOpTable[a] = VK_ATTACHMENT_STORE_OP_STORE;
  }

  for(uint32_t s = 0; s < ci.subpassCount; ++s)
  {
    const VkAttachmentReference *pColorAttachments = ci.pSubpasses[s].pColorAttachments;
    const VkAttachmentReference *pResolveAttachments = ci.pSubpasses[s].pResolveAttachments;
    const VkAttachmentReference *pDepthStencilAttachment = ci.pSubpasses[s].pDepthStencilAttachment;

    if(pColorAttachments)
    {
      const VkAttachmentReference *pColorRunner = pColorAttachments;
      const VkAttachmentReference *pColorEnd = pColorRunner + ci.pSubpasses[s].colorAttachmentCount;

      while(pColorRunner != pColorEnd)
      {
        uint32_t index = pColorRunner->attachment;
        if(index < ci.attachmentCount)
        {
          loadOpTable[index] = ci.pAttachments[index].loadOp;
          storeOpTable[index] = ci.pAttachments[index].storeOp;

          if(multiviewViewMaskTable)
          {
            multiviewViewMaskTable[index] |= multiview->pViewMasks[s];
          }
        }
        ++pColorRunner;
      }
    }
    if(pResolveAttachments)
    {
      const VkAttachmentReference *pResolveRunner = pResolveAttachments;
      const VkAttachmentReference *pResolveEnd =
          pResolveRunner + ci.pSubpasses[s].colorAttachmentCount;

      while(pResolveRunner != pResolveEnd)
      {
        uint32_t index = pResolveRunner->attachment;
        if(index < ci.attachmentCount)
        {
          loadOpTable[index] = ci.pAttachments[index].loadOp;
          storeOpTable[index] = ci.pAttachments[index].storeOp;

          if(multiviewViewMaskTable)
          {
            multiviewViewMaskTable[index] |= multiview->pViewMasks[s];
          }
        }
        ++pResolveRunner;
      }
    }
    if(pDepthStencilAttachment)
    {
      uint32_t index = pDepthStencilAttachment->attachment;

      if(index < ci.attachmentCount)
      {
        VkAttachmentLoadOp depthStencilLoadOp = ci.pAttachments[index].loadOp;
        VkAttachmentStoreOp depthStencilStoreOp = ci.pAttachments[index].storeOp;

        // make depthstencil VK_ATTACHMENT_LOAD_OP_LOAD if either depth or stencil is
        // VK_ATTACHMENT_LOAD_OP_LOAD
        if(depthStencilLoadOp != VK_ATTACHMENT_LOAD_OP_LOAD &&
           IsStencilFormat(ci.pAttachments[index].format))
        {
          depthStencilLoadOp = ci.pAttachments[index].stencilLoadOp;
        }
        // similarly for store
        if(depthStencilStoreOp != VK_ATTACHMENT_STORE_OP_STORE &&
           IsStencilFormat(ci.pAttachments[index].format))
        {
          depthStencilStoreOp = ci.pAttachments[index].stencilStoreOp;
        }

        loadOpTable[index] = depthStencilLoadOp;
        storeOpTable[index] = depthStencilStoreOp;

        if(multiviewViewMaskTable)
        {
          multiviewViewMaskTable[index] |= multiview->pViewMasks[s];
        }
      }
    }
  }
}

RenderPassInfo::RenderPassInfo(const VkRenderPassCreateInfo2 &ci)
{
  // *2 in case we need separate barriers for depth and stencil, +1 for the terminating null
  // attachment info
  uint32_t arrayCount = ci.attachmentCount * 2 + 1;
  imageAttachments = new AttachmentInfo[arrayCount];
  RDCEraseMem(imageAttachments, arrayCount * sizeof(imageAttachments[0]));

  // need to keep a table for the index remap, because imageAttachments won't have the same
  // order as ci.pAttachments
  rdcarray<uint32_t> indexRemapTable;
  indexRemapTable.fill(ci.attachmentCount, 0xFFFFFFFF);

  for(uint32_t i = 0, a = 0; i < ci.attachmentCount; i++, a++)
  {
    imageAttachments[a].record = NULL;
    imageAttachments[a].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
    imageAttachments[a].barrier.oldLayout = ci.pAttachments[i].initialLayout;
    imageAttachments[a].barrier.newLayout = ci.pAttachments[i].finalLayout;
    imageAttachments[a].barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    imageAttachments[a].barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    imageAttachments[a].format = ci.pAttachments[i].format;
    imageAttachments[a].samples = ci.pAttachments[i].samples;

    indexRemapTable[i] = a;

    // VK_KHR_separate_depth_stencil_layouts
    VkAttachmentDescriptionStencilLayout *separateStencil =
        (VkAttachmentDescriptionStencilLayout *)FindNextStruct(
            &ci.pAttachments[i], VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT);

    if(separateStencil)
    {
      imageAttachments[a].barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;

      // add a separate barrier for stencil
      a++;

      imageAttachments[a].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
      imageAttachments[a].barrier.oldLayout = separateStencil->stencilInitialLayout;
      imageAttachments[a].barrier.newLayout = separateStencil->stencilFinalLayout;
      imageAttachments[a].barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
      imageAttachments[a].barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
      imageAttachments[a].barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
    }
  }

  // if any subpass' viewMask is non-zero, then multiview is enabled
  multiviewViewMaskTable = NULL;
  for(uint32_t s = 0; s < ci.subpassCount; ++s)
  {
    if(ci.pSubpasses[s].viewMask)
    {
      multiviewViewMaskTable = new uint32_t[arrayCount];
      RDCEraseMem(multiviewViewMaskTable, arrayCount * sizeof(multiviewViewMaskTable[0]));
      break;
    }
  }

  loadOpTable = new VkAttachmentLoadOp[arrayCount];
  storeOpTable = new VkAttachmentStoreOp[arrayCount];

  // we only care about which attachment doesn't have LOAD specificed, so we
  // assume all attachments have VK_ATTACHMENT_LOAD_OP_LOAD until proven otherwise.
  // similarly for store
  for(uint32_t a = 0; a < arrayCount; ++a)
  {
    loadOpTable[a] = VK_ATTACHMENT_LOAD_OP_LOAD;
    storeOpTable[a] = VK_ATTACHMENT_STORE_OP_STORE;
  }

  for(uint32_t s = 0; s < ci.subpassCount; ++s)
  {
    const VkAttachmentReference2 *pColorAttachments = ci.pSubpasses[s].pColorAttachments;
    const VkAttachmentReference2 *pResolveAttachments = ci.pSubpasses[s].pResolveAttachments;
    const VkAttachmentReference2 *pDepthStencilAttachment = ci.pSubpasses[s].pDepthStencilAttachment;

    if(pColorAttachments)
    {
      const VkAttachmentReference2 *pColorRunner = pColorAttachments;
      const VkAttachmentReference2 *pColorEnd = pColorRunner + ci.pSubpasses[s].colorAttachmentCount;

      while(pColorRunner != pColorEnd)
      {
        uint32_t index = pColorRunner->attachment;
        if(index < ci.attachmentCount)
        {
          uint32_t remappedIndex = indexRemapTable[index];
          RDCASSERT(remappedIndex < arrayCount);

          loadOpTable[remappedIndex] = ci.pAttachments[index].loadOp;
          storeOpTable[remappedIndex] = ci.pAttachments[index].storeOp;

          if(multiviewViewMaskTable)
          {
            multiviewViewMaskTable[remappedIndex] |= ci.pSubpasses[s].viewMask;
          }
        }
        ++pColorRunner;
      }
    }
    if(pResolveAttachments)
    {
      const VkAttachmentReference2 *pResolveRunner = pResolveAttachments;
      const VkAttachmentReference2 *pResolveEnd =
          pResolveRunner + ci.pSubpasses[s].colorAttachmentCount;

      while(pResolveRunner != pResolveEnd)
      {
        uint32_t index = pResolveRunner->attachment;
        if(index < ci.attachmentCount)
        {
          uint32_t remappedIndex = indexRemapTable[index];
          RDCASSERT(remappedIndex < arrayCount);

          loadOpTable[remappedIndex] = ci.pAttachments[index].loadOp;
          storeOpTable[remappedIndex] = ci.pAttachments[index].storeOp;

          if(multiviewViewMaskTable)
          {
            multiviewViewMaskTable[remappedIndex] |= ci.pSubpasses[s].viewMask;
          }
        }
        ++pResolveRunner;
      }
    }
    if(pDepthStencilAttachment)
    {
      uint32_t index = pDepthStencilAttachment->attachment;

      if(index < ci.attachmentCount)
      {
        VkAttachmentLoadOp depthStencilLoadOp = ci.pAttachments[index].loadOp;
        VkAttachmentStoreOp depthStencilStoreOp = ci.pAttachments[index].storeOp;
        VkAttachmentLoadOp stencilLoadOp = ci.pAttachments[index].stencilLoadOp;
        VkAttachmentStoreOp stencilStoreOp = ci.pAttachments[index].stencilStoreOp;

        uint32_t remappedIndex = indexRemapTable[index];
        RDCASSERT(remappedIndex < arrayCount);

        if(IsStencilFormat(ci.pAttachments[index].format))
        {
          // VK_KHR_separate_depth_stencil_layouts
          VkAttachmentDescriptionStencilLayout *separateStencil =
              (VkAttachmentDescriptionStencilLayout *)FindNextStruct(
                  &ci.pAttachments[index], VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT);

          if(separateStencil)
          {
            loadOpTable[remappedIndex + 1] = stencilLoadOp;
            storeOpTable[remappedIndex + 1] = stencilStoreOp;
          }
          else
          {
            // make depthstencil VK_ATTACHMENT_LOAD_OP_LOAD if either depth or stencil is
            // VK_ATTACHMENT_LOAD_OP_LOAD
            if(depthStencilLoadOp != VK_ATTACHMENT_LOAD_OP_LOAD)
            {
              depthStencilLoadOp = stencilLoadOp;
            }
            if(depthStencilStoreOp != VK_ATTACHMENT_STORE_OP_STORE)
            {
              depthStencilStoreOp = stencilStoreOp;
            }
          }
        }

        loadOpTable[remappedIndex] = depthStencilLoadOp;
        storeOpTable[remappedIndex] = depthStencilStoreOp;

        if(multiviewViewMaskTable)
        {
          multiviewViewMaskTable[remappedIndex] |= ci.pSubpasses[s].viewMask;
        }
      }
    }
  }
}

RenderPassInfo::~RenderPassInfo()
{
  delete[] imageAttachments;
  delete[] loadOpTable;
  delete[] storeOpTable;
  delete[] multiviewViewMaskTable;
}

FramebufferInfo::FramebufferInfo(const VkFramebufferCreateInfo &ci)
{
  // *2 in case we need separate barriers for depth and stencil, +1 for the terminating null
  // attachment info
  uint32_t arrayCount = ci.attachmentCount * 2 + 1;

  imageAttachments = new AttachmentInfo[arrayCount];
  RDCEraseMem(imageAttachments, arrayCount * sizeof(imageAttachments[0]));

  width = ci.width;
  height = ci.height;
  layers = ci.layers;
}
FramebufferInfo::~FramebufferInfo()
{
  delete[] imageAttachments;
}

bool FramebufferInfo::AttachmentFullyReferenced(size_t attachmentIndex, VkResourceRecord *att,
                                                VkImageSubresourceRange viewRange,
                                                const RenderPassInfo *rpi)
{
  // if framebuffer doesn't reference the entire image
  if(att->resInfo->imageInfo.extent.width != width || att->resInfo->imageInfo.extent.height != height)
  {
    return false;
  }
  // if view doesn't reference the entire image
  if(att->viewRange.baseArrayLayer != 0 ||
     att->viewRange.layerCount() != (uint32_t)att->resInfo->imageInfo.layerCount ||
     att->viewRange.baseMipLevel != 0 ||
     att->viewRange.levelCount() != (uint32_t)att->resInfo->imageInfo.levelCount)
  {
    return false;
  }
  if(rpi->multiviewViewMaskTable)
  {
    // check and make sure all views are referenced by the renderpass
    uint32_t renderpass_viewmask = rpi->multiviewViewMaskTable[attachmentIndex];
    return Bits::CountOnes(renderpass_viewmask) == att->resInfo->imageInfo.layerCount;
  }
  return viewRange.layerCount == layers;
}

int ImgRefs::GetAspectCount() const
{
  int aspectCount = 0;
  for(auto aspectIt = ImageAspectFlagIter::begin(aspectMask);
      aspectIt != ImageAspectFlagIter::end(); ++aspectIt)
  {
    ++aspectCount;
  }
  return aspectCount;
}

int ImgRefs::AspectIndex(VkImageAspectFlagBits aspect) const
{
  int aspectIndex = 0;
  if(areAspectsSplit)
  {
    for(auto aspectIt = ImageAspectFlagIter::begin(aspectMask);
        aspectIt != ImageAspectFlagIter::end(); ++aspectIt)
    {
      if(*aspectIt == aspect)
        break;
      ++aspectIndex;
    }
  }
  return aspectIndex;
}

int ImgRefs::SubresourceIndex(int aspectIndex, int level, int layer) const
{
  if(!areAspectsSplit)
    aspectIndex = 0;
  int splitLevelCount = 1;
  if(areLevelsSplit)
    splitLevelCount = imageInfo.levelCount;
  else
    level = 0;
  int splitLayerCount = 1;
  if(areLayersSplit)
    splitLayerCount = imageInfo.layerCount;
  else
    layer = 0;
  return (aspectIndex * splitLevelCount + level) * splitLayerCount + layer;
}

InitReqType ImgRefs::SubresourceRangeMaxInitReq(VkImageSubresourceRange range, InitPolicy policy,
                                                bool initialized) const
{
  InitReqType initReq = eInitReq_None;
  rdcarray<int> splitAspectIndices;
  if(areAspectsSplit)
  {
    int aspectIndex = 0;
    for(auto aspectIt = ImageAspectFlagIter::begin(aspectMask);
        aspectIt != ImageAspectFlagIter::end(); ++aspectIt, ++aspectIndex)
    {
      if(((*aspectIt) & range.aspectMask) != 0)
        splitAspectIndices.push_back(aspectIndex);
    }
  }
  else
  {
    splitAspectIndices.push_back(0);
  }

  int splitLevelCount = 1;
  if(areLevelsSplit || range.baseMipLevel != 0 || range.levelCount < (uint32_t)imageInfo.levelCount)
  {
    splitLevelCount = range.levelCount;
  }
  int splitLayerCount = 1;
  if(areLayersSplit || range.baseArrayLayer != 0 || range.layerCount < (uint32_t)imageInfo.layerCount)
  {
    splitLayerCount = range.layerCount;
  }
  for(auto aspectIndexIt = splitAspectIndices.begin(); aspectIndexIt != splitAspectIndices.end();
      ++aspectIndexIt)
  {
    for(int level = range.baseMipLevel; level < splitLevelCount; ++level)
    {
      for(int layer = range.baseArrayLayer; layer < splitLayerCount; ++layer)
      {
        initReq =
            RDCMAX(initReq, SubresourceInitReq(*aspectIndexIt, level, layer, policy, initialized));
      }
    }
  }
  return initReq;
}

rdcarray<rdcpair<VkImageSubresourceRange, InitReqType> > ImgRefs::SubresourceRangeInitReqs(
    VkImageSubresourceRange range, InitPolicy policy, bool initialized) const
{
  VkImageSubresourceRange out(range);
  rdcarray<rdcpair<VkImageSubresourceRange, InitReqType> > res;
  rdcarray<rdcpair<int, VkImageAspectFlags> > splitAspects;
  if(areAspectsSplit)
  {
    int aspectIndex = 0;
    for(auto aspectIt = ImageAspectFlagIter::begin(aspectMask);
        aspectIt != ImageAspectFlagIter::end(); ++aspectIt, ++aspectIndex)
    {
      if(((*aspectIt) & range.aspectMask) != 0)
        splitAspects.push_back({aspectIndex, (VkImageAspectFlags)*aspectIt});
    }
  }
  else
  {
    splitAspects.push_back({0, aspectMask});
  }

  int splitLevelCount = 1;
  if(areLevelsSplit || range.baseMipLevel != 0 || range.levelCount < (uint32_t)imageInfo.levelCount)
  {
    splitLevelCount = range.levelCount;
    out.levelCount = 1;
  }
  int splitLayerCount = 1;
  if(areLayersSplit || range.baseArrayLayer != 0 || range.layerCount < (uint32_t)imageInfo.layerCount)
  {
    splitLayerCount = range.layerCount;
    out.layerCount = 1;
  }
  for(auto aspectIt = splitAspects.begin(); aspectIt != splitAspects.end(); ++aspectIt)
  {
    int aspectIndex = aspectIt->first;
    out.aspectMask = aspectIt->second;
    for(int level = range.baseMipLevel; level < splitLevelCount; ++level)
    {
      out.baseMipLevel = level;
      for(int layer = range.baseArrayLayer; layer < splitLayerCount; ++layer)
      {
        out.baseArrayLayer = layer;
        res.push_back(
            make_rdcpair(out, SubresourceInitReq(aspectIndex, level, layer, policy, initialized)));
      }
    }
  }
  return res;
}

void ImgRefs::Split(bool splitAspects, bool splitLevels, bool splitLayers)
{
  int newSplitAspectCount = 1;
  if(splitAspects || areAspectsSplit)
  {
    newSplitAspectCount = GetAspectCount();
  }

  int oldSplitLevelCount = areLevelsSplit ? imageInfo.levelCount : 1;
  int newSplitLevelCount = splitLevels ? imageInfo.levelCount : oldSplitLevelCount;

  int oldSplitLayerCount = areLayersSplit ? imageInfo.layerCount : 1;
  int newSplitLayerCount = splitLayers ? imageInfo.layerCount : oldSplitLayerCount;

  int newSize = newSplitAspectCount * newSplitLevelCount * newSplitLayerCount;
  if(newSize == (int)rangeRefs.size())
    return;
  rangeRefs.resize(newSize);

  for(int newAspectIndex = newSplitAspectCount - 1; newAspectIndex >= 0; --newAspectIndex)
  {
    int oldAspectIndex = areAspectsSplit ? newAspectIndex : 0;
    for(int newLevel = newSplitLevelCount - 1; newLevel >= 0; --newLevel)
    {
      int oldLevel = areLevelsSplit ? newLevel : 0;
      for(int newLayer = newSplitLayerCount - 1; newLayer >= 0; --newLayer)
      {
        int oldLayer = areLayersSplit ? newLayer : 0;
        int oldIndex =
            (oldAspectIndex * oldSplitLevelCount + oldLevel) * oldSplitLayerCount + oldLayer;
        int newIndex =
            (newAspectIndex * newSplitLevelCount + newLevel) * newSplitLayerCount + newLayer;
        rangeRefs[newIndex] = rangeRefs[oldIndex];
      }
    }
  }
  areAspectsSplit = newSplitAspectCount > 1;
  areLevelsSplit = newSplitLevelCount > 1;
  areLayersSplit = newSplitLayerCount > 1;
}

VkResourceRecord::~VkResourceRecord()
{
  // bufferviews and imageviews have non-owning pointers to the sparseinfo struct
  if(resType == eResBuffer || resType == eResImage)
    SAFE_DELETE(resInfo);

  if(resType == eResInstance || resType == eResDevice || resType == eResPhysicalDevice)
    SAFE_DELETE(instDevInfo);

  if(resType == eResSwapchain)
    SAFE_DELETE(swapInfo);

  if(resType == eResDeviceMemory && memMapState)
  {
    FreeAlignedBuffer(memMapState->refData);

    SAFE_DELETE(memMapState);
  }

  if(resType == eResCommandBuffer)
    SAFE_DELETE(cmdInfo);

  if(resType == eResFramebuffer)
    SAFE_DELETE(framebufferInfo);

  if(resType == eResRenderPass)
    SAFE_DELETE(renderPassInfo);

  // only the descriptor set layout actually owns this pointer, descriptor sets
  // have a pointer to it but don't own it
  if(resType == eResDescriptorSetLayout)
    SAFE_DELETE(descInfo->layout);

  if(resType == eResDescriptorSetLayout || resType == eResDescriptorSet)
    SAFE_DELETE(descInfo);

  if(resType == eResPipelineLayout)
    SAFE_DELETE(pipeLayoutInfo);

  if(resType == eResDescriptorPool)
    SAFE_DELETE(descPoolInfo);

  if(resType == eResDescUpdateTemplate)
    SAFE_DELETE(descTemplateInfo);

  if(resType == eResCommandPool)
    SAFE_DELETE(cmdPoolInfo);
}

void VkResourceRecord::MarkImageFrameReferenced(VkResourceRecord *img, const ImageRange &range,
                                                FrameRefType refType)
{
  ResourceId id = img->GetResourceID();

  // mark backing memory. For dedicated images we always treat the memory as read only so
  // we don't try and include its initial contents.
  if(img->dedicated)
    MarkResourceFrameReferenced(img->baseResource, eFrameRef_Read);
  else
    MarkResourceFrameReferenced(img->baseResource, refType);

  if(img->resInfo && img->resInfo->IsSparse())
    cmdInfo->sparse.insert(img->resInfo);

  ImageSubresourceRange range2(range);

  FrameRefType maxRef = MarkImageReferenced(cmdInfo->imageStates, id, img->resInfo->imageInfo,
                                            range2, VK_QUEUE_FAMILY_IGNORED, refType);

  // maintain the reference type of the image itself as the maximum reference type of any
  // subresource
  MarkResourceFrameReferenced(id, maxRef, ComposeFrameRefsDisjoint);
}

void VkResourceRecord::MarkImageViewFrameReferenced(VkResourceRecord *view, const ImageRange &range,
                                                    FrameRefType refType)
{
  ResourceId img = view->baseResource;
  ResourceId mem = view->baseResourceMem;

  // mark image view as read
  MarkResourceFrameReferenced(view->GetResourceID(), eFrameRef_Read);

  // mark memory backing image as read only so we don't try and include its initial contents just
  // because of an image's writes
  MarkResourceFrameReferenced(mem, eFrameRef_Read);

  ImageSubresourceRange imgRange;
  imgRange.aspectMask = view->viewRange.aspectMask;

  imgRange.baseMipLevel = range.baseMipLevel;
  imgRange.levelCount = range.levelCount;
  SanitiseLevelRange(imgRange.baseMipLevel, imgRange.levelCount, view->viewRange.levelCount());
  imgRange.baseMipLevel += view->viewRange.baseMipLevel;

  if(view->resInfo->imageInfo.imageType == VK_IMAGE_TYPE_3D &&
     view->viewRange.viewType() != VK_IMAGE_VIEW_TYPE_3D)
  {
    imgRange.baseDepthSlice = range.baseArrayLayer;
    imgRange.sliceCount = range.layerCount;
    SanitiseLayerRange(imgRange.baseDepthSlice, imgRange.sliceCount, view->viewRange.layerCount());
    imgRange.baseDepthSlice += view->viewRange.baseArrayLayer;
  }
  else
  {
    imgRange.baseArrayLayer = range.baseArrayLayer;
    imgRange.layerCount = range.layerCount;
    SanitiseLayerRange(imgRange.baseArrayLayer, imgRange.layerCount, view->viewRange.layerCount());
    imgRange.baseArrayLayer += view->viewRange.baseArrayLayer;
  }
  imgRange.Sanitise(view->resInfo->imageInfo);

  FrameRefType maxRef = MarkImageReferenced(cmdInfo->imageStates, img, view->resInfo->imageInfo,
                                            imgRange, VK_QUEUE_FAMILY_IGNORED, refType);

  // maintain the reference type of the image itself as the maximum reference type of any
  // subresource
  MarkResourceFrameReferenced(img, maxRef, ComposeFrameRefsDisjoint);
}

void VkResourceRecord::MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset,
                                                 VkDeviceSize size, FrameRefType refType)
{
  FrameRefType maxRef = MarkMemoryReferenced(cmdInfo->memFrameRefs, mem, offset, size, refType);
  MarkResourceFrameReferenced(mem, maxRef, ComposeFrameRefsDisjoint);
}

void VkResourceRecord::MarkBufferFrameReferenced(VkResourceRecord *buf, VkDeviceSize offset,
                                                 VkDeviceSize size, FrameRefType refType)
{
  // mark buffer just as read
  MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read);

  if(size == VK_WHOLE_SIZE)
  {
    size = buf->memSize;
  }
  if(buf->resInfo && buf->resInfo->IsSparse())
    cmdInfo->sparse.insert(buf->resInfo);
  if(buf->baseResource != ResourceId())
    MarkMemoryFrameReferenced(buf->baseResource, buf->memOffset + offset, size, refType);
}

void VkResourceRecord::MarkBufferImageCopyFrameReferenced(VkResourceRecord *buf,
                                                          VkResourceRecord *img, uint32_t regionCount,
                                                          const VkBufferImageCopy *regions,
                                                          FrameRefType bufRefType,
                                                          FrameRefType imgRefType)
{
  // mark buffer just as read
  MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read);

  VkFormat imgFormat = img->resInfo->imageInfo.format;

  for(uint32_t ri = 0; ri < regionCount; ri++)
  {
    const VkBufferImageCopy &region = regions[ri];

    ImageRange range(region.imageSubresource);
    range.offset = region.imageOffset;
    range.extent = region.imageExtent;

    MarkImageFrameReferenced(img, range, imgRefType);

    VkFormat regionFormat = imgFormat;
    uint32_t plane = 0;
    switch(region.imageSubresource.aspectMask)
    {
      case VK_IMAGE_ASPECT_STENCIL_BIT: regionFormat = VK_FORMAT_S8_UINT; break;
      case VK_IMAGE_ASPECT_DEPTH_BIT: regionFormat = GetDepthOnlyFormat(imgFormat); break;
      case VK_IMAGE_ASPECT_PLANE_1_BIT: plane = 1; break;
      case VK_IMAGE_ASPECT_PLANE_2_BIT: plane = 2; break;
      default: break;
    }

    // The shape of the texel blocks;
    // non-block formats are treated as having 1x1 blocks
    BlockShape blockShape = GetBlockShape(regionFormat, plane);

    // width of copied region, in blocks
    uint32_t widthInBlocks = (region.imageExtent.width + blockShape.width - 1) / blockShape.width;

    // width of copied region, in bytes (in the buffer);
    uint32_t widthInBytes = blockShape.bytes * widthInBlocks;

    // height of copied region, in blocks
    uint32_t heightInBlocks = (region.imageExtent.height + blockShape.height - 1) / blockShape.height;

    // total number of depth slices to be copied.
    uint32_t sliceCount = region.imageExtent.depth * region.imageSubresource.layerCount;

    // stride_y: number of bytes in the buffer between the start of one row of
    // blocks and the next. The buffer may have space for more blocks per row than
    // are actually being copied (specified by bufferRowLength).
    uint32_t stride_y;
    if(region.bufferRowLength == 0)
      stride_y = widthInBytes;
    else
      stride_y = blockShape.bytes * region.bufferRowLength;

    // stride_z: number of bytes in the buffer between the start of one depth
    // slice and the next. The buffer may have space for more rows per slice
    // than are actually being copied (specified by bufferImageHeight).
    uint32_t stride_z;
    if(region.bufferImageHeight == 0)
      stride_z = stride_y * heightInBlocks;
    else
      stride_z = stride_y * region.bufferImageHeight;

    // memory offset of the first byte to be copied to/from the buffer
    VkDeviceSize startRegion = buf->memOffset + region.bufferOffset;

    if(stride_z == widthInBytes * heightInBlocks)
    {
      // no gaps between slices nor between rows; single copy for entire region
      MarkMemoryFrameReferenced(buf->baseResource, startRegion,
                                widthInBytes * heightInBlocks * sliceCount, bufRefType);
    }
    else if(stride_y == widthInBytes)
    {
      // gaps between slices, but no gaps between rows; separate copies per slice
      for(uint32_t z = 0; z < sliceCount; z++)
      {
        VkDeviceSize startSlice = startRegion + z * stride_z;
        MarkMemoryFrameReferenced(buf->baseResource, startSlice, widthInBytes * heightInBlocks,
                                  bufRefType);
      }
    }
    else
    {
      // gaps between rows; separate copies for each row in each slice
      for(uint32_t z = 0; z < sliceCount; z++)
      {
        VkDeviceSize startSlice = startRegion + z * stride_z;
        for(uint32_t y = 0; y < heightInBlocks; y++)
        {
          VkDeviceSize startRow = startSlice + y * stride_y;
          MarkMemoryFrameReferenced(buf->baseResource, startRow, widthInBytes, bufRefType);
        }
      }
    }
  }
}

void VkResourceRecord::MarkBufferViewFrameReferenced(VkResourceRecord *bufView, FrameRefType refType)
{
  // mark the VkBufferView and VkBuffer as read
  MarkResourceFrameReferenced(bufView->GetResourceID(), eFrameRef_Read);
  if(bufView->baseResource != ResourceId())
    MarkResourceFrameReferenced(bufView->baseResource, eFrameRef_Read);

  if(bufView->resInfo && bufView->resInfo->IsSparse())
    cmdInfo->sparse.insert(bufView->resInfo);
  if(bufView->baseResourceMem != ResourceId())
    MarkMemoryFrameReferenced(bufView->baseResourceMem, bufView->memOffset, bufView->memSize,
                              refType);
}

void ResourceInfo::Update(uint32_t numBindings, const VkSparseImageMemoryBind *pBindings,
                          std::set<ResourceId> &memories)
{
  // update texel mappings
  for(uint32_t i = 0; i < numBindings; i++)
  {
    const VkSparseImageMemoryBind &bind = pBindings[i];

    Sparse::PageTable &table = getSparseTableForAspect(bind.subresource.aspectMask);

    const uint32_t sub =
        table.calcSubresource(bind.subresource.arrayLayer, bind.subresource.mipLevel);

    table.setImageBoxRange(
        sub, {(uint32_t)bind.offset.x, (uint32_t)bind.offset.y, (uint32_t)bind.offset.z},
        {bind.extent.width, bind.extent.height, bind.extent.depth}, GetResID(bind.memory),
        bind.memoryOffset, false);

    memories.insert(GetResID(bind.memory));
  }
}

void ResourceInfo::Update(uint32_t numBindings, const VkSparseMemoryBind *pBindings,
                          std::set<ResourceId> &memories)
{
  // update mip tail mappings
  const bool isBuffer = (imageInfo.extent.width == 0);

  for(uint32_t i = 0; i < numBindings; i++)
  {
    const VkSparseMemoryBind &bind = pBindings[i];

    memories.insert(GetResID(bind.memory));

    // don't need to figure out which aspect we're in if we only have one table
    if(isBuffer || altSparseAspects.empty())
    {
      sparseTable.setMipTailRange(bind.resourceOffset, GetResID(bind.memory), bind.memoryOffset,
                                  bind.size, false);
    }
    else
    {
      bool found = false;

      // ask each table if this offset is within its range
      for(size_t a = 0; a <= altSparseAspects.size(); a++)
      {
        Sparse::PageTable &table =
            a < altSparseAspects.size() ? altSparseAspects[a].table : sparseTable;

        if(table.isByteOffsetInResource(bind.resourceOffset))
        {
          found = true;
          table.setMipTailRange(bind.resourceOffset, GetResID(bind.memory), bind.memoryOffset,
                                bind.size, false);
        }
      }

      // just in case, if we don't find it in any then assume it's metadata
      if(!found)
        getSparseTableForAspect(VK_IMAGE_ASPECT_METADATA_BIT)
            .setMipTailRange(bind.resourceOffset, GetResID(bind.memory), bind.memoryOffset,
                             bind.size, false);
    }
  }
}

FrameRefType MarkImageReferenced(rdcflatmap<ResourceId, ImageState> &imageStates, ResourceId img,
                                 const ImageInfo &imageInfo, const ImageSubresourceRange &range,
                                 uint32_t queueFamilyIndex, FrameRefType refType)
{
  if(refType == eFrameRef_None)
    return refType;
  auto it = imageStates.find(img);
  if(it == imageStates.end())
    it = imageStates.insert({img, ImageState(VK_NULL_HANDLE, imageInfo, refType)}).first;
  it->second.Update(range, ImageSubresourceState(queueFamilyIndex, UNKNOWN_PREV_IMG_LAYOUT, refType),
                    ComposeFrameRefs);
  return it->second.maxRefType;
}

#if ENABLED(ENABLE_UNIT_TESTS)

#undef None
#undef Always

#include "catch/catch.hpp"

TEST_CASE("Vulkan formats", "[format][vulkan]")
{
  // must be updated by hand
  std::initializer_list<VkFormat> formats = {
      VK_FORMAT_UNDEFINED,
      VK_FORMAT_R4G4_UNORM_PACK8,
      VK_FORMAT_R4G4B4A4_UNORM_PACK16,
      VK_FORMAT_B4G4R4A4_UNORM_PACK16,
      VK_FORMAT_R5G6B5_UNORM_PACK16,
      VK_FORMAT_B5G6R5_UNORM_PACK16,
      VK_FORMAT_R5G5B5A1_UNORM_PACK16,
      VK_FORMAT_B5G5R5A1_UNORM_PACK16,
      VK_FORMAT_A1R5G5B5_UNORM_PACK16,
      VK_FORMAT_R8_UNORM,
      VK_FORMAT_R8_SNORM,
      VK_FORMAT_R8_USCALED,
      VK_FORMAT_R8_SSCALED,
      VK_FORMAT_R8_UINT,
      VK_FORMAT_R8_SINT,
      VK_FORMAT_R8_SRGB,
      VK_FORMAT_R8G8_UNORM,
      VK_FORMAT_R8G8_SNORM,
      VK_FORMAT_R8G8_USCALED,
      VK_FORMAT_R8G8_SSCALED,
      VK_FORMAT_R8G8_UINT,
      VK_FORMAT_R8G8_SINT,
      VK_FORMAT_R8G8_SRGB,
      VK_FORMAT_R8G8B8_UNORM,
      VK_FORMAT_R8G8B8_SNORM,
      VK_FORMAT_R8G8B8_USCALED,
      VK_FORMAT_R8G8B8_SSCALED,
      VK_FORMAT_R8G8B8_UINT,
      VK_FORMAT_R8G8B8_SINT,
      VK_FORMAT_R8G8B8_SRGB,
      VK_FORMAT_B8G8R8_UNORM,
      VK_FORMAT_B8G8R8_SNORM,
      VK_FORMAT_B8G8R8_USCALED,
      VK_FORMAT_B8G8R8_SSCALED,
      VK_FORMAT_B8G8R8_UINT,
      VK_FORMAT_B8G8R8_SINT,
      VK_FORMAT_B8G8R8_SRGB,
      VK_FORMAT_R8G8B8A8_UNORM,
      VK_FORMAT_R8G8B8A8_SNORM,
      VK_FORMAT_R8G8B8A8_USCALED,
      VK_FORMAT_R8G8B8A8_SSCALED,
      VK_FORMAT_R8G8B8A8_UINT,
      VK_FORMAT_R8G8B8A8_SINT,
      VK_FORMAT_R8G8B8A8_SRGB,
      VK_FORMAT_B8G8R8A8_UNORM,
      VK_FORMAT_B8G8R8A8_SNORM,
      VK_FORMAT_B8G8R8A8_USCALED,
      VK_FORMAT_B8G8R8A8_SSCALED,
      VK_FORMAT_B8G8R8A8_UINT,
      VK_FORMAT_B8G8R8A8_SINT,
      VK_FORMAT_B8G8R8A8_SRGB,
      VK_FORMAT_A8B8G8R8_UNORM_PACK32,
      VK_FORMAT_A8B8G8R8_SNORM_PACK32,
      VK_FORMAT_A8B8G8R8_USCALED_PACK32,
      VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
      VK_FORMAT_A8B8G8R8_UINT_PACK32,
      VK_FORMAT_A8B8G8R8_SINT_PACK32,
      VK_FORMAT_A8B8G8R8_SRGB_PACK32,
      VK_FORMAT_A2R10G10B10_UNORM_PACK32,
      VK_FORMAT_A2R10G10B10_SNORM_PACK32,
      VK_FORMAT_A2R10G10B10_USCALED_PACK32,
      VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
      VK_FORMAT_A2R10G10B10_UINT_PACK32,
      VK_FORMAT_A2R10G10B10_SINT_PACK32,
      VK_FORMAT_A2B10G10R10_UNORM_PACK32,
      VK_FORMAT_A2B10G10R10_SNORM_PACK32,
      VK_FORMAT_A2B10G10R10_USCALED_PACK32,
      VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
      VK_FORMAT_A2B10G10R10_UINT_PACK32,
      VK_FORMAT_A2B10G10R10_SINT_PACK32,
      VK_FORMAT_R16_UNORM,
      VK_FORMAT_R16_SNORM,
      VK_FORMAT_R16_USCALED,
      VK_FORMAT_R16_SSCALED,
      VK_FORMAT_R16_UINT,
      VK_FORMAT_R16_SINT,
      VK_FORMAT_R16_SFLOAT,
      VK_FORMAT_R16G16_UNORM,
      VK_FORMAT_R16G16_SNORM,
      VK_FORMAT_R16G16_USCALED,
      VK_FORMAT_R16G16_SSCALED,
      VK_FORMAT_R16G16_UINT,
      VK_FORMAT_R16G16_SINT,
      VK_FORMAT_R16G16_SFLOAT,
      VK_FORMAT_R16G16B16_UNORM,
      VK_FORMAT_R16G16B16_SNORM,
      VK_FORMAT_R16G16B16_USCALED,
      VK_FORMAT_R16G16B16_SSCALED,
      VK_FORMAT_R16G16B16_UINT,
      VK_FORMAT_R16G16B16_SINT,
      VK_FORMAT_R16G16B16_SFLOAT,
      VK_FORMAT_R16G16B16A16_UNORM,
      VK_FORMAT_R16G16B16A16_SNORM,
      VK_FORMAT_R16G16B16A16_USCALED,
      VK_FORMAT_R16G16B16A16_SSCALED,
      VK_FORMAT_R16G16B16A16_UINT,
      VK_FORMAT_R16G16B16A16_SINT,
      VK_FORMAT_R16G16B16A16_SFLOAT,
      VK_FORMAT_R32_UINT,
      VK_FORMAT_R32_SINT,
      VK_FORMAT_R32_SFLOAT,
      VK_FORMAT_R32G32_UINT,
      VK_FORMAT_R32G32_SINT,
      VK_FORMAT_R32G32_SFLOAT,
      VK_FORMAT_R32G32B32_UINT,
      VK_FORMAT_R32G32B32_SINT,
      VK_FORMAT_R32G32B32_SFLOAT,
      VK_FORMAT_R32G32B32A32_UINT,
      VK_FORMAT_R32G32B32A32_SINT,
      VK_FORMAT_R32G32B32A32_SFLOAT,
      VK_FORMAT_R64_UINT,
      VK_FORMAT_R64_SINT,
      VK_FORMAT_R64_SFLOAT,
      VK_FORMAT_R64G64_UINT,
      VK_FORMAT_R64G64_SINT,
      VK_FORMAT_R64G64_SFLOAT,
      VK_FORMAT_R64G64B64_UINT,
      VK_FORMAT_R64G64B64_SINT,
      VK_FORMAT_R64G64B64_SFLOAT,
      VK_FORMAT_R64G64B64A64_UINT,
      VK_FORMAT_R64G64B64A64_SINT,
      VK_FORMAT_R64G64B64A64_SFLOAT,
      VK_FORMAT_B10G11R11_UFLOAT_PACK32,
      VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
      VK_FORMAT_D16_UNORM,
      VK_FORMAT_X8_D24_UNORM_PACK32,
      VK_FORMAT_D32_SFLOAT,
      VK_FORMAT_S8_UINT,
      VK_FORMAT_D16_UNORM_S8_UINT,
      VK_FORMAT_D24_UNORM_S8_UINT,
      VK_FORMAT_D32_SFLOAT_S8_UINT,
      VK_FORMAT_BC1_RGB_UNORM_BLOCK,
      VK_FORMAT_BC1_RGB_SRGB_BLOCK,
      VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
      VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
      VK_FORMAT_BC2_UNORM_BLOCK,
      VK_FORMAT_BC2_SRGB_BLOCK,
      VK_FORMAT_BC3_UNORM_BLOCK,
      VK_FORMAT_BC3_SRGB_BLOCK,
      VK_FORMAT_BC4_UNORM_BLOCK,
      VK_FORMAT_BC4_SNORM_BLOCK,
      VK_FORMAT_BC5_UNORM_BLOCK,
      VK_FORMAT_BC5_SNORM_BLOCK,
      VK_FORMAT_BC6H_UFLOAT_BLOCK,
      VK_FORMAT_BC6H_SFLOAT_BLOCK,
      VK_FORMAT_BC7_UNORM_BLOCK,
      VK_FORMAT_BC7_SRGB_BLOCK,
      VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
      VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
      VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
      VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
      VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
      VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
      VK_FORMAT_EAC_R11_UNORM_BLOCK,
      VK_FORMAT_EAC_R11_SNORM_BLOCK,
      VK_FORMAT_EAC_R11G11_UNORM_BLOCK,
      VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
      VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
      VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
      VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
      VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
      VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
      VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
      VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
      VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
      VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
      VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
      VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
      VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
      VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
      VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
      VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
      VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
      VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
      VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
      VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
      VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
      VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
      VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
      VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
      VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
      VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
      VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
      VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
      VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
      VK_FORMAT_G8B8G8R8_422_UNORM,
      VK_FORMAT_B8G8R8G8_422_UNORM,
      VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
      VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
      VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
      VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
      VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
      VK_FORMAT_G8_B8R8_2PLANE_444_UNORM,
      VK_FORMAT_R10X6_UNORM_PACK16,
      VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
      VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
      VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
      VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
      VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
      VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
      VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
      VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
      VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
      VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16,
      VK_FORMAT_R12X4_UNORM_PACK16,
      VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
      VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
      VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
      VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
      VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
      VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
      VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
      VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
      VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
      VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16,
      VK_FORMAT_G16B16G16R16_422_UNORM,
      VK_FORMAT_B16G16R16G16_422_UNORM,
      VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
      VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
      VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
      VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
      VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
      VK_FORMAT_G16_B16R16_2PLANE_444_UNORM,
      VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,
      VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,
      VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,
      VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,
      VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,
      VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,
      VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,
      VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,
      VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK,
      VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK,
  };

  SECTION("Only VK_FORMAT_UNDEFINED is ResourceFormatType::Undefined")
  {
    for(VkFormat f : formats)
    {
      ResourceFormat fmt = MakeResourceFormat(f);

      if(f == VK_FORMAT_UNDEFINED)
        CHECK(fmt.type == ResourceFormatType::Undefined);
      else
        CHECK(fmt.type != ResourceFormatType::Undefined);
    }
  };

  SECTION("MakeVkFormat is reflexive with MakeResourceFormat")
  {
    for(VkFormat f : formats)
    {
      VkFormat original = f;
      ResourceFormat fmt = MakeResourceFormat(f);

      // astc and pvrtc are not properly supported, collapse to a single type
      if((f >= VK_FORMAT_ASTC_4x4_UNORM_BLOCK && f <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK) ||
         (f >= VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK && f <= VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK))
      {
        CHECK(fmt.type == ResourceFormatType::ASTC);
        continue;
      }
      if(f >= VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG && f <= VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG)
      {
        CHECK(fmt.type == ResourceFormatType::PVRTC);
        continue;
      }

      VkFormat reconstructed = MakeVkFormat(fmt);

      // we are OK with remapping these variants to another similar one, where our format doesn't
      // have enough flexibility to represent the exact type (as a trade-off vs simplicity of
      // processing/storage).
      if(f == VK_FORMAT_A1R5G5B5_UNORM_PACK16)
      {
        CHECK(reconstructed == VK_FORMAT_R5G5B5A1_UNORM_PACK16);
      }
      else if(f == VK_FORMAT_A8B8G8R8_UNORM_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_UNORM);
      }
      else if(f == VK_FORMAT_A8B8G8R8_SNORM_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_SNORM);
      }
      else if(f == VK_FORMAT_A8B8G8R8_USCALED_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_USCALED);
      }
      else if(f == VK_FORMAT_A8B8G8R8_SSCALED_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_SSCALED);
      }
      else if(f == VK_FORMAT_A8B8G8R8_UINT_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_UINT);
      }
      else if(f == VK_FORMAT_A8B8G8R8_SINT_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_SINT);
      }
      else if(f == VK_FORMAT_A8B8G8R8_SRGB_PACK32)
      {
        CHECK(reconstructed == VK_FORMAT_R8G8B8A8_SRGB);
      }
      else
      {
        CHECK(reconstructed == original);
      }
    }
  };

  SECTION("MakeVkFormat concurs with helpers")
  {
    for(VkFormat f : formats)
    {
      ResourceFormat fmt = MakeResourceFormat(f);

      INFO("Format is " << ToStr(f));

      if(IsBlockFormat(f))
      {
        INFO("Format type is " << ToStr(fmt.type));

        bool bcn = fmt.type >= ResourceFormatType::BC1 && fmt.type <= ResourceFormatType::BC7;

        CHECK((bcn || fmt.type == ResourceFormatType::ASTC || fmt.type == ResourceFormatType::EAC ||
               fmt.type == ResourceFormatType::ETC2 || fmt.type == ResourceFormatType::PVRTC));
      }

      if(IsYUVFormat(f))
      {
        CHECK(fmt.type >= ResourceFormatType::YUV8);
        CHECK(fmt.type <= ResourceFormatType::YUV16);
      }

      if(IsDepthOrStencilFormat(f))
      {
        CHECK(fmt.compType == CompType::Depth);
      }
      else if(IsUIntFormat(f))
      {
        CHECK(fmt.compType == CompType::UInt);
      }
      else if(IsSIntFormat(f))
      {
        CHECK(fmt.compType == CompType::SInt);
      }

      if(IsSRGBFormat(f))
      {
        CHECK(fmt.SRGBCorrected());
      }
    }
  };

  SECTION("GetByteSize return expected values for regular formats")
  {
    for(VkFormat f : formats)
    {
      ResourceFormat fmt = MakeResourceFormat(f);

      if(fmt.type != ResourceFormatType::Regular)
        continue;

      INFO("Format is " << ToStr(f));

      // byte size for D24X8 is the same as D24S8!
      if(fmt.compByteWidth == 3)
        fmt.compByteWidth = 4;

      uint32_t size = fmt.compCount * fmt.compByteWidth * 123 * 456;

      CHECK(size == GetByteSize(123, 456, 1, f, 0));
    }
  };

  SECTION("GetByteSize for BCn formats")
  {
    const uint32_t width = 24, height = 24;

    // reference: 24x24 = 576, 576/2 = 288

    const uint32_t bcnsizes[] = {
        288,    // VK_FORMAT_BC1_RGB_UNORM_BLOCK
        288,    // VK_FORMAT_BC1_RGB_SRGB_BLOCK
        288,    // VK_FORMAT_BC1_RGBA_UNORM_BLOCK
        288,    // VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 0.5 byte/px
        576,    // VK_FORMAT_BC2_UNORM_BLOCK
        576,    // VK_FORMAT_BC2_SRGB_BLOCK = 1 byte/px
        576,    // VK_FORMAT_BC3_UNORM_BLOCK
        576,    // VK_FORMAT_BC3_SRGB_BLOCK = 1 byte/px
        288,    // VK_FORMAT_BC4_UNORM_BLOCK
        288,    // VK_FORMAT_BC4_SNORM_BLOCK = 0.5 byte/px
        576,    // VK_FORMAT_BC5_UNORM_BLOCK
        576,    // VK_FORMAT_BC5_SNORM_BLOCK = 1 byte/px
        576,    // VK_FORMAT_BC6H_UFLOAT_BLOCK
        576,    // VK_FORMAT_BC6H_SFLOAT_BLOCK = 1 byte/px
        576,    // VK_FORMAT_BC7_UNORM_BLOCK
        576,    // VK_FORMAT_BC7_SRGB_BLOCK = 1 byte/px
    };

    int i = 0;
    for(VkFormat f : {
            VK_FORMAT_BC1_RGB_UNORM_BLOCK,
            VK_FORMAT_BC1_RGB_SRGB_BLOCK,
            VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
            VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
            VK_FORMAT_BC2_UNORM_BLOCK,
            VK_FORMAT_BC2_SRGB_BLOCK,
            VK_FORMAT_BC3_UNORM_BLOCK,
            VK_FORMAT_BC3_SRGB_BLOCK,
            VK_FORMAT_BC4_UNORM_BLOCK,
            VK_FORMAT_BC4_SNORM_BLOCK,
            VK_FORMAT_BC5_UNORM_BLOCK,
            VK_FORMAT_BC5_SNORM_BLOCK,
            VK_FORMAT_BC6H_UFLOAT_BLOCK,
            VK_FORMAT_BC6H_SFLOAT_BLOCK,
            VK_FORMAT_BC7_UNORM_BLOCK,
            VK_FORMAT_BC7_SRGB_BLOCK,
        })
    {
      INFO("Format is " << ToStr(f));

      CHECK(bcnsizes[i++] == GetByteSize(width, height, 1, f, 0));
    }
  };

  SECTION("GetByteSize for YUV formats")
  {
    const uint32_t width = 24, height = 24;

    const uint32_t yuvsizes[] = {
        1152,    // VK_FORMAT_G8B8G8R8_422_UNORM (4:2:2 8-bit packed)
        1152,    // VK_FORMAT_B8G8R8G8_422_UNORM (4:2:2 8-bit packed)
        864,     // VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM (4:2:0 8-bit 3-plane)
        864,     // VK_FORMAT_G8_B8R8_2PLANE_420_UNORM (4:2:0 8-bit 2-plane)
        1152,    // VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM (4:2:2 8-bit 3-plane)
        1152,    // VK_FORMAT_G8_B8R8_2PLANE_422_UNORM (4:2:2 8-bit 2-plane)
        1728,    // VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM (4:4:4 8-bit 3-plane)
        1728,    // VK_FORMAT_G8_B8R8_2PLANE_444_UNORM (4:4:4 8-bit 2-plane)
        1152,    // VK_FORMAT_R10X6_UNORM_PACK16 (4:4:4 10-bit packed)
        2304,    // VK_FORMAT_R10X6G10X6_UNORM_2PACK16 (4:4:4 10-bit packed)
        4608,    // VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 (4:4:4 10-bit packed)
        2304,    // VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 (4:2:2 10-bit packed)
        2304,    // VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 (4:2:2 10-bit packed)
        1728,    // VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 (4:2:0 10-bit 3-plane)
        1728,    // VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 (4:2:0 10-bit 2-plane)
        2304,    // VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 (4:2:2 10-bit 3-plane)
        2304,    // VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 (4:2:2 10-bit 2-plane)
        3456,    // VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 (4:4:4 10-bit 3-plane)
        3456,    // VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 (4:4:4 10-bit 2-plane)
        1152,    // VK_FORMAT_R12X4_UNORM_PACK16 (4:4:4 12-bit packed)
        2304,    // VK_FORMAT_R12X4G12X4_UNORM_2PACK16 (4:4:4 12-bit packed)
        4608,    // VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 (4:4:4 12-bit packed)
        2304,    // VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 (4:2:2 12-bit packed)
        2304,    // VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 (4:2:2 12-bit packed)
        1728,    // VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 (4:2:0 12-bit 3-plane)
        1728,    // VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 (4:2:0 12-bit 2-plane)
        2304,    // VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 (4:2:2 12-bit 3-plane)
        2304,    // VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 (4:2:2 12-bit 2-plane)
        3456,    // VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 (4:4:4 12-bit 3-plane)
        3456,    // VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 (4:4:4 12-bit 2-plane)
        2304,    // VK_FORMAT_G16B16G16R16_422_UNORM (4:2:2 16-bit packed)
        2304,    // VK_FORMAT_B16G16R16G16_422_UNORM (4:2:2 16-bit packed)
        1728,    // VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM (4:2:0 16-bit 3-plane)
        1728,    // VK_FORMAT_G16_B16R16_2PLANE_420_UNORM (4:2:0 16-bit 2-plane)
        2304,    // VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM (4:2:2 16-bit 3-plane)
        2304,    // VK_FORMAT_G16_B16R16_2PLANE_422_UNORM (4:2:2 16-bit 2-plane)
        3456,    // VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM (4:4:4 16-bit 3-plane)
        3456,    // VK_FORMAT_G16_B16R16_2PLANE_444_UNORM (4:4:4 16-bit 2-plane)
    };

    int i = 0;
    for(VkFormat f : {
            VK_FORMAT_G8B8G8R8_422_UNORM,
            VK_FORMAT_B8G8R8G8_422_UNORM,
            VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
            VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
            VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
            VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
            VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
            VK_FORMAT_G8_B8R8_2PLANE_444_UNORM,
            VK_FORMAT_R10X6_UNORM_PACK16,
            VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
            VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
            VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
            VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
            VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
            VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
            VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
            VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
            VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
            VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16,
            VK_FORMAT_R12X4_UNORM_PACK16,
            VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
            VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
            VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
            VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
            VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
            VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
            VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
            VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
            VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
            VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16,
            VK_FORMAT_G16B16G16R16_422_UNORM,
            VK_FORMAT_B16G16R16G16_422_UNORM,
            VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
            VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
            VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
            VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
            VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
            VK_FORMAT_G16_B16R16_2PLANE_444_UNORM,
        })
    {
      INFO("Format is " << ToStr(f));

      CHECK(yuvsizes[i++] == GetByteSize(width, height, 1, f, 0));
    }
  };

  SECTION("GetPlaneByteSize for planar YUV formats")
  {
    const uint32_t width = 24, height = 24;

    rdcarray<rdcpair<VkFormat, rdcarray<uint32_t> > > tests = {
        {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, {576, 144, 144}},
        {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, {576, 288}},
        {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, {576, 288, 288}},
        {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, {576, 576}},
        {VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, {576, 576, 576}},
        {VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, {576, 1152}},
        {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, {1152, 288, 288}},
        {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, {1152, 576}},
        {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, {1152, 576, 576}},
        {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, {1152, 1152}},
        {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, {1152, 1152, 1152}},
        {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, {1152, 2304}},
        {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, {1152, 288, 288}},
        {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, {1152, 576}},
        {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, {1152, 576, 576}},
        {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, {1152, 1152}},
        {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, {1152, 1152, 1152}},
        {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, {1152, 2304}},
        {VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, {1152, 288, 288}},
        {VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, {1152, 576}},
        {VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, {1152, 576, 576}},
        {VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, {1152, 1152}},
        {VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, {1152, 1152, 1152}},
        {VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, {1152, 2304}},
    };

    for(rdcpair<VkFormat, rdcarray<uint32_t> > e : tests)
    {
      INFO("Format is " << ToStr(e.first));
      for(uint32_t p = 0; p < e.second.size(); p++)
        CHECK(e.second[p] == GetPlaneByteSize(width, height, 1, e.first, 0, p));
    }
  };

  SECTION("GetPlaneByteSize is consistent with GetByteSize")
  {
    const uint32_t width = 24, height = 24;

    for(VkFormat f : formats)
    {
      if(f == VK_FORMAT_UNDEFINED)
        continue;

      INFO("Format is " << ToStr(f));

      uint32_t planeCount = GetYUVPlaneCount(f);

      uint32_t planeSum = 0;
      for(uint32_t p = 0; p < planeCount; p++)
        planeSum += GetPlaneByteSize(width, height, 1, f, 0, p);

      CHECK(planeSum == GetByteSize(width, height, 1, f, 0));
    }
  };
};

#endif    // ENABLED(ENABLE_UNIT_TESTS)
