Merge pull request #843 from billhollings/master

Accurately populate Vulkan VkFormatProperties and capabilities.
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
index 39b0214..75830bb 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
@@ -545,7 +545,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "API-Samples" */;
 			compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
index cd9f6b1..620a035 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
index 9e3343d..283d573 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
index 3be4f3a..afb8606 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
@@ -234,7 +234,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cube" */;
 			compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
index 0280935..b6cace4 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
index f5b92b4..7a4cf00 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
index 06e807d..9058306 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
@@ -265,7 +265,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hologram" */;
 			compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
index e04eb5b..38a9ae3 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
index c6531c9..7ad255a 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 9555af7..eea6263 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -19,6 +19,9 @@
 
 Released 2020/03/30
 
+- Accurately populate Vulkan `VkFormatProperties` from `MTLPixelFormat` capabilities, 
+  taking into consideration variations across `MTLDevice` Features Sets.
+- Validate format capabilities for MSAA, renderpass attachments, and `vkCmdResolveImage()`.
 - Fix issue where immutable samplers are removed during descriptor update.
 - Guard against Metal validation assertion from reuse of query number within a single `MTLRenderEncoder`.
 - Increase value of `VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment` 
@@ -28,6 +31,7 @@
 - Fix memory leak when pre-filling `MTLCommandBuffers` using `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS`.
 - Update the `README.md` and `MoltenVK_Runtime_UserGuide.md` documents to clarify that 
   **MoltenVK** is not a fully-compliant implementation of *Vulkan*.
+- Support Xcode 11.4.
 
 
 
diff --git a/ExternalDependencies.xcodeproj/project.pbxproj b/ExternalDependencies.xcodeproj/project.pbxproj
index df55215..7e81b48 100644
--- a/ExternalDependencies.xcodeproj/project.pbxproj
+++ b/ExternalDependencies.xcodeproj/project.pbxproj
@@ -2966,7 +2966,7 @@
 		A9F55D25198BE6A7004EC31B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 				ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
 				TargetAttributes = {
 					A972A7E421CEC72F0013AB25 = {
diff --git "a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme" "b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
index 3b2aa3e..18a6d08 100644
--- "a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
+++ "b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
index 27269b7..fab5380 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
index 73b694c..2313055 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
index db75dc5..2ebf29f 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
index cbe74af..944ddf4 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
index f943b8a..9f89d19 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
index 937b24b..03437e5 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
index 62f0e9f..cbfbdd3 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
index bc9dce8..dc8c0d1 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
index 1405451..4a85559 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index c71c6d5..321eea6 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -850,7 +850,7 @@
 		A9F55D25198BE6A7004EC31B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 				ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
 				TargetAttributes = {
 					A9B8EE091A98D796009C5A02 = {
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
index 3c6827a..fcfb674 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
index bbd8694..6e4b83f 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h
index 55320a4..3a162f2 100644
--- a/MoltenVK/MoltenVK/API/mvk_datatypes.h
+++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h
@@ -163,21 +163,8 @@
  */
 size_t mvkMTLPixelFormatBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer);
 
-/** 
- * Returns the default properties for the specified Vulkan format.
- *
- * Not all MTLPixelFormats returned by this function are supported by all GPU's, and, as a
- * result, MoltenVK may return a different value from the vkGetPhysicalDeviceFormatProperties()
- * function than is returned here. Use the vkGetPhysicalDeviceFormatProperties() function to
- * return the properties for a particular GPU.
- *
- * Setting assumeGPUSupportsDefault to true allows the default format properties to be returned.
- * The assumeGPUSupportsDefault flag can be set to false if it is already known that the format
- * is not supported by a particular GPU for images, in which case all of the returned properties
- * will be disabled, except possibly VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT, which may be supported
- * for the format even without image support.
- */
-VkFormatProperties mvkVkFormatProperties(VkFormat vkFormat, bool assumeGPUSupportsDefault = true);
+/** Returns the default properties for the specified Vulkan format. */
+VkFormatProperties mvkVkFormatProperties(VkFormat vkFormat);
 
 /** Returns the name of the specified Vulkan format. */
 const char* mvkVkFormatName(VkFormat vkFormat);
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 5db0911..f23b2eb 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -467,6 +467,11 @@
 
     _dstImage->getTransferDescriptorData(_transferImageData);
 	_transferImageData.samples = _srcImage->getSampleCount();
+
+	// Validate
+	if ( !mvkAreAllFlagsEnabled(getPixelFormats()->getMTLPixelFormatCapabilities(_dstImage->getMTLPixelFormat()), kMVKMTLFmtCapsResolve) ) {
+		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdResolveImage(): %s cannot be used as a resolve destination on this device.", getPixelFormats()->getVkFormatName(_dstImage->getVkFormat())));
+	}
 }
 
 /**
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
index 9f75f5a..1bf9bd1 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
@@ -112,25 +112,21 @@
  * This structure can be used as a key in a std::map and std::unordered_map.
  */
 typedef struct MVKRPSKeyClearAtt {
-    uint16_t attachmentMTLPixelFormats[kMVKClearAttachmentCount];
+	uint16_t flags;				// bitcount > kMVKClearAttachmentLayeredRenderingBitIndex
 	uint16_t mtlSampleCount;
-    uint16_t flags;			// bitcount > kMVKClearAttachmentLayeredRenderingBitIndex
+	uint16_t attachmentMTLPixelFormats[kMVKClearAttachmentCount];
 
     const static uint32_t bitFlag = 1;
 
-    void enableAttachment(uint32_t attIdx) { mvkEnableFlag(flags, bitFlag << attIdx); }
+    void enableAttachment(uint32_t attIdx) { mvkEnableFlags(flags, bitFlag << attIdx); }
 
     bool isAttachmentEnabled(uint32_t attIdx) { return mvkIsAnyFlagEnabled(flags, bitFlag << attIdx); }
 
-	void enableLayeredRendering() { mvkEnableFlag(flags, bitFlag << kMVKClearAttachmentLayeredRenderingBitIndex); }
+	void enableLayeredRendering() { mvkEnableFlags(flags, bitFlag << kMVKClearAttachmentLayeredRenderingBitIndex); }
 
 	bool isLayeredRenderingEnabled() { return mvkIsAnyFlagEnabled(flags, bitFlag << kMVKClearAttachmentLayeredRenderingBitIndex); }
 
-    bool operator==(const MVKRPSKeyClearAtt& rhs) const {
-        return ((flags == rhs.flags) &&
-				(mtlSampleCount == rhs.mtlSampleCount) &&
-                (memcmp(attachmentMTLPixelFormats, rhs.attachmentMTLPixelFormats, sizeof(attachmentMTLPixelFormats)) == 0));
-    }
+    bool operator==(const MVKRPSKeyClearAtt& rhs) const { return mvkAreEqual(this, &rhs); }
 
 	std::size_t hash() const {
 		std::size_t hash = mvkHash(&flags);
@@ -212,9 +208,7 @@
     MVKMTLStencilDescriptorData frontFaceStencilData;
     MVKMTLStencilDescriptorData backFaceStencilData;
 
-	bool operator==(const MVKMTLDepthStencilDescriptorData& rhs) const {
-		return (memcmp(this, &rhs, sizeof(*this)) == 0);
-	}
+	bool operator==(const MVKMTLDepthStencilDescriptorData& rhs) const { return mvkAreEqual(this, &rhs); }
 
 	std::size_t hash() const {
 		return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t));
@@ -270,9 +264,7 @@
     VkSampleCountFlagBits    samples;
     VkImageUsageFlags        usage;
 
-    bool operator==(const MVKImageDescriptorData& rhs) const {
-        return (memcmp(this, &rhs, sizeof(*this)) == 0);
-    }
+    bool operator==(const MVKImageDescriptorData& rhs) const { return mvkAreEqual(this, &rhs); }
 
 	std::size_t hash() const {
 		return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t));
@@ -307,9 +299,7 @@
     VkDeviceSize             size;
     VkBufferUsageFlags       usage;
 
-    bool operator==(const MVKBufferDescriptorData& rhs) const {
-        return (memcmp(this, &rhs, sizeof(*this)) == 0);
-    }
+    bool operator==(const MVKBufferDescriptorData& rhs) const { return mvkAreEqual(this, &rhs); }
 
 	std::size_t hash() const {
 		return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t));
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
index c829d32..9fdf6af 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
@@ -55,12 +55,12 @@
 #if MVK_MACOS
 	// Textures must not use shared memory
 	if (mvkIsAnyFlagEnabled(_usage, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
-		mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
+		mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
 	}
 #endif
 #if MVK_IOS
 	// Memoryless storage is not allowed for buffers
-	mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
+	mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
 #endif
 	return VK_SUCCESS;
 }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index c2be49a..b2fc00e 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -719,7 +719,6 @@
 
 /**
  * This mixin class adds the ability for an object to track the device that created it.
- * Implementation supports an instance where the device is null.
  *
  * As a mixin, this class should only be used as a component of multiple inheritance.
  * Any class that inherits from this class should also inherit from MVKBaseObject.
@@ -733,18 +732,19 @@
 	inline MVKDevice* getDevice() { return _device; }
 
 	/** Returns the underlying Metal device. */
-	inline id<MTLDevice> getMTLDevice() { return _device ? _device->getMTLDevice() : nil; }
+	inline id<MTLDevice> getMTLDevice() { return _device->getMTLDevice(); }
 
 	/** Returns info about the pixel format supported by the physical device. */
-	inline MVKPixelFormats* getPixelFormats() { return _device ? _device->getPixelFormats() : mvkPlatformPixelFormats(); }
+	inline MVKPixelFormats* getPixelFormats() { return _device->getPixelFormats(); }
 
 	/** Constructs an instance for the specified device. */
-    MVKDeviceTrackingMixin(MVKDevice* device) : _device(device) {}
+    MVKDeviceTrackingMixin(MVKDevice* device) : _device(device) { assert(_device); }
 
 	virtual ~MVKDeviceTrackingMixin() {}
 
 protected:
 	virtual MVKBaseObject* getBaseObject() = 0;
+
 	MVKDevice* _device;
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 33e3369..bc81118 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -223,11 +223,11 @@
 }
 
 VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
-                                                     VkImageType type,
-                                                     VkImageTiling tiling,
-                                                     VkImageUsageFlags usage,
-                                                     VkImageCreateFlags flags,
-                                                     VkImageFormatProperties* pImageFormatProperties) {
+													 VkImageType type,
+													 VkImageTiling tiling,
+													 VkImageUsageFlags usage,
+													 VkImageCreateFlags flags,
+													 VkImageFormatProperties* pImageFormatProperties) {
 
 	if ( !_pixelFormats.vkFormatIsSupported(format) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 
@@ -245,14 +245,16 @@
 														  VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
 														  VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
 
-    VkPhysicalDeviceLimits* pLimits = &_properties.limits;
-    VkExtent3D maxExt;
-	uint32_t maxLevels;
+	VkPhysicalDeviceLimits* pLimits = &_properties.limits;
+	VkExtent3D maxExt = { 1, 1, 1};
+	uint32_t maxLevels = 1;
 	uint32_t maxLayers = hasAttachmentUsage ? pLimits->maxFramebufferLayers : pLimits->maxImageArrayLayers;
 
-	VkSampleCountFlags sampleCounts = _metalFeatures.supportedSampleCounts;
-    switch (type) {
-        case VK_IMAGE_TYPE_1D:
+	bool supportsMSAA =  mvkAreAllFlagsEnabled(_pixelFormats.getVkFormatCapabilities(format), kMVKMTLFmtCapsMSAA);
+	VkSampleCountFlags sampleCounts = supportsMSAA ? _metalFeatures.supportedSampleCounts : VK_SAMPLE_COUNT_1_BIT;
+
+	switch (type) {
+		case VK_IMAGE_TYPE_1D:
 			maxExt.height = 1;
 			maxExt.depth = 1;
 			if (mvkTreatTexture1DAs2D()) {
@@ -273,16 +275,17 @@
 				if (mvkFmt == kMVKFormatDepthStencil) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 				if (mvkFmt == kMVKFormatCompressed) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 			}
-            break;
-        case VK_IMAGE_TYPE_2D:
-            if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ) {
-                maxExt.width = pLimits->maxImageDimensionCube;
-                maxExt.height = pLimits->maxImageDimensionCube;
-            } else {
-                maxExt.width = pLimits->maxImageDimension2D;
-                maxExt.height = pLimits->maxImageDimension2D;
-            }
-            maxExt.depth = 1;
+			break;
+
+		case VK_IMAGE_TYPE_2D:
+			if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ) {
+				maxExt.width = pLimits->maxImageDimensionCube;
+				maxExt.height = pLimits->maxImageDimensionCube;
+			} else {
+				maxExt.width = pLimits->maxImageDimension2D;
+				maxExt.height = pLimits->maxImageDimension2D;
+			}
+			maxExt.depth = 1;
 			if (tiling == VK_IMAGE_TILING_LINEAR) {
 				// Linear textures have additional restrictions under Metal:
 				// - They may not be depth/stencil or compressed textures.
@@ -310,12 +313,13 @@
 				}
 				maxLevels = mvkMipmapLevels3D(maxExt);
 			}
-            break;
-        case VK_IMAGE_TYPE_3D:
-            // Metal does not allow linear tiling on 3D textures
-            if (tiling == VK_IMAGE_TILING_LINEAR) {
-                return VK_ERROR_FORMAT_NOT_SUPPORTED;
-            }
+			break;
+
+		case VK_IMAGE_TYPE_3D:
+			// Metal does not allow linear tiling on 3D textures
+			if (tiling == VK_IMAGE_TILING_LINEAR) {
+				return VK_ERROR_FORMAT_NOT_SUPPORTED;
+			}
 			// Metal does not allow compressed or depth/stencil formats on 3D textures
 			if (mvkFmt == kMVKFormatDepthStencil
 #if MVK_IOS
@@ -330,35 +334,25 @@
 				return VK_ERROR_FORMAT_NOT_SUPPORTED;
 			}
 #endif
-            maxExt.width = pLimits->maxImageDimension3D;
-            maxExt.height = pLimits->maxImageDimension3D;
-            maxExt.depth = pLimits->maxImageDimension3D;
+			maxExt.width = pLimits->maxImageDimension3D;
+			maxExt.height = pLimits->maxImageDimension3D;
+			maxExt.depth = pLimits->maxImageDimension3D;
 			maxLevels = mvkMipmapLevels3D(maxExt);
-            maxLayers = 1;
-            sampleCounts = VK_SAMPLE_COUNT_1_BIT;
-            break;
-        default:
-			// Metal does not allow linear tiling on anything but 2D textures
-			if (tiling == VK_IMAGE_TILING_LINEAR) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
-
-			// Metal does not allow compressed or depth/stencil formats on anything but 2D textures
-			if (mvkFmt == kMVKFormatDepthStencil || mvkFmt == kMVKFormatCompressed) {
-				return VK_ERROR_FORMAT_NOT_SUPPORTED;
-			}
-            maxExt = { 1, 1, 1};
-            maxLayers = 1;
-			maxLevels = 1;
+			maxLayers = 1;
 			sampleCounts = VK_SAMPLE_COUNT_1_BIT;
-            break;
-    }
+			break;
 
-    pImageFormatProperties->maxExtent = maxExt;
-    pImageFormatProperties->maxMipLevels = maxLevels;
-    pImageFormatProperties->maxArrayLayers = maxLayers;
-    pImageFormatProperties->sampleCounts = sampleCounts;
-    pImageFormatProperties->maxResourceSize = kMVKUndefinedLargeUInt64;
+		default:
+			return VK_ERROR_FORMAT_NOT_SUPPORTED;	// Illegal VkImageType
+	}
 
-    return VK_SUCCESS;
+	pImageFormatProperties->maxExtent = maxExt;
+	pImageFormatProperties->maxMipLevels = maxLevels;
+	pImageFormatProperties->maxArrayLayers = maxLayers;
+	pImageFormatProperties->sampleCounts = sampleCounts;
+	pImageFormatProperties->maxResourceSize = kMVKUndefinedLargeUInt64;
+
+	return VK_SUCCESS;
 }
 
 VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
@@ -385,9 +379,9 @@
 
 // If the image format info links portability image view info, test if an image view of that configuration is supported
 bool MVKPhysicalDevice::getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo) {
-	auto* next = (VkStructureType*)pImageFormatInfo->pNext;
+	auto* next = (MVKVkAPIStructHeader*)pImageFormatInfo->pNext;
 	while (next) {
-		switch ((int32_t)*next) {
+		switch ((uint32_t)next->sType) {
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_SUPPORT_EXTX: {
 				auto* portImgViewInfo = (VkPhysicalDeviceImageViewSupportEXTX*)next;
 
@@ -396,7 +390,7 @@
 					.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 					.pNext = (VkStructureType*)portImgViewInfo->pNext,
 					.flags = portImgViewInfo->flags,
-					.image = VK_NULL_HANDLE,
+					.image = nullptr,
 					.viewType = portImgViewInfo->viewType,
 					.format = portImgViewInfo->format,
 					.components = portImgViewInfo->components,
@@ -407,11 +401,15 @@
 						.baseArrayLayer = 0,
 						.layerCount = 1},
 				};
-				MVKImageView imgView(VK_NULL_HANDLE, &viewInfo, _mvkInstance->getMoltenVKConfiguration());
-				return imgView.getConfigurationResult() == VK_SUCCESS;
+				MTLPixelFormat mtlPixFmt;
+				bool useSwizzle;
+				return (MVKImageView::validateSwizzledMTLPixelFormat(&viewInfo, &_pixelFormats, this,
+																	 _metalFeatures.nativeTextureSwizzle,
+																	 _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle,
+																	 mtlPixFmt, useSwizzle) == VK_SUCCESS);
 			}
 			default:
-				next = (VkStructureType*)((VkPhysicalDeviceFeatures2*)next)->pNext;
+				next = (MVKVkAPIStructHeader*)next->pNext;
 				break;
 		}
 	}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index 535aeb8..1b991d4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -323,6 +323,30 @@
 	 */
 	void populateMTLRenderPassAttachmentDescriptorResolve(MTLRenderPassAttachmentDescriptor* mtlAttDesc);
 
+	/**
+	 * Returns, in mtlPixFmt, a MTLPixelFormat, based on the MTLPixelFormat converted from
+	 * the VkFormat, but possibly modified by the swizzles defined in the VkComponentMapping
+	 * of the VkImageViewCreateInfo.
+	 *
+	 * Metal prior to version 3.0 does not support native per-texture swizzles, so if the swizzle
+	 * is not an identity swizzle, this function attempts to find an alternate MTLPixelFormat that
+	 * coincidentally matches the swizzled format.
+	 *
+	 * If a replacement MTLFormat was found, it is returned and useSwizzle is set to false.
+	 * If a replacement MTLFormat could not be found, the original MTLPixelFormat is returned,
+	 * and the useSwizzle is set to true, indicating that either native or shader swizzling
+	 * should be used for this image view.
+	 *
+	 * This is a static function that can be used to validate image view formats prior to creating one.
+	 */
+	static VkResult validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
+												   MVKPixelFormats* mvkPixFmts,
+												   MVKVulkanAPIObject* apiObject,
+												   bool hasNativeSwizzleSupport,
+												   bool hasShaderSwizzleSupport,
+												   MTLPixelFormat& mtlPixFmt,
+												   bool& useSwizzle);
+
 
 #pragma mark Construction
 
@@ -336,10 +360,6 @@
 	void propogateDebugName() override;
 	id<MTLTexture> newMTLTexture();
 	void initMTLTextureViewSupport();
-    MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format,
-											 VkComponentMapping components,
-											 bool& useSwizzle,
-											 const MVKConfiguration* pMVKConfig);
 	void validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo);
 
     MVKImage* _image;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index c14abb3..c2410a4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -178,13 +178,13 @@
 #if MVK_MACOS
 	// Metal on macOS does not provide native support for host-coherent memory, but Vulkan requires it for Linear images
 	if ( !_isLinear ) {
-		mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
+		mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
 	}
 #endif
 #if MVK_IOS
 	// Only transient attachments may use memoryless storage
 	if (!mvkAreAllFlagsEnabled(_usage, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ) {
-		mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
+		mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
 	}
 #endif
 	return VK_SUCCESS;
@@ -429,20 +429,20 @@
 		pixFmts->mtlPixelFormatIsDepthFormat(_mtlPixelFormat) &&
 		pixFmts->mtlPixelFormatIsStencilFormat(_mtlPixelFormat)) {
 
-		mvkDisableFlag(usage, MTLTextureUsagePixelFormatView);
+		mvkDisableFlags(usage, MTLTextureUsagePixelFormatView);
 	}
 
 	// If this format doesn't support being rendered to, disable MTLTextureUsageRenderTarget.
 	if ( !getSupportsAnyFormatFeature(VK_FORMAT_FEATURE_BLIT_DST_BIT |
 									  VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
 									  VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ) {
-		mvkDisableFlag(usage, MTLTextureUsageRenderTarget);
+		mvkDisableFlags(usage, MTLTextureUsageRenderTarget);
 	}
 
 #if MVK_MACOS
 	// If this is a 3D compressed texture, tell Metal we might write to it.
 	if (_is3DCompressed) {
-		mvkEnableFlag(usage, MTLTextureUsageShaderWrite);
+		mvkEnableFlags(usage, MTLTextureUsageShaderWrite);
 	}
 #endif
 
@@ -634,7 +634,7 @@
 	_mtlPixelFormat = pixFmts->getMTLPixelFormatFromVkFormat(pCreateInfo->format);
 	_usage = pCreateInfo->usage;
 
-	_is3DCompressed = (getImageType() == VK_IMAGE_TYPE_3D) && (pixFmts->getFormatTypeFromVkFormat(pCreateInfo->format) == kMVKFormatCompressed) && !getDevice()->_pMetalFeatures->native3DCompressedTextures;
+	_is3DCompressed = (getImageType() == VK_IMAGE_TYPE_3D) && (pixFmts->getFormatTypeFromVkFormat(pCreateInfo->format) == kMVKFormatCompressed) && !_device->_pMetalFeatures->native3DCompressedTextures;
 	_isDepthStencilAttachment = (mvkAreAllFlagsEnabled(pCreateInfo->usage, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ||
 								 mvkAreAllFlagsEnabled(pixFmts->getVkFormatProperties(pCreateInfo->format).optimalTilingFeatures, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT));
 	_canSupportMTLTextureView = !_isDepthStencilAttachment || _device->_pMetalFeatures->stencilViews;
@@ -705,7 +705,7 @@
 	if (isCompressed && !is2D) {
 		if (getImageType() != VK_IMAGE_TYPE_3D) {
 			setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, compressed formats may only be used with 2D or 3D images."));
-		} else if (!getDevice()->_pMetalFeatures->native3DCompressedTextures && !mvkCanDecodeFormat(pCreateInfo->format)) {
+		} else if (!_device->_pMetalFeatures->native3DCompressedTextures && !mvkCanDecodeFormat(pCreateInfo->format)) {
 			setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, the %s compressed format may only be used with 2D images.", getPixelFormats()->getVkFormatName(pCreateInfo->format)));
 		}
 	}
@@ -896,7 +896,7 @@
         mtlTextureType = MTLTextureType3D;
         sliceRange = NSMakeRange(0, 1);
     }
-    if (getDevice()->_pMetalFeatures->nativeTextureSwizzle && _packedSwizzle) {
+    if (_device->_pMetalFeatures->nativeTextureSwizzle && _packedSwizzle) {
         return [_image->getMTLTexture() newTextureViewWithPixelFormat: _mtlPixelFormat
                                                           textureType: mtlTextureType
                                                                levels: NSMakeRange(_subresourceRange.baseMipLevel, _subresourceRange.levelCount)
@@ -913,27 +913,24 @@
 
 #pragma mark Construction
 
-// device and _image may be nil when a temporary instance
-// is constructed to validate image view capabilities
 MVKImageView::MVKImageView(MVKDevice* device,
 						   const VkImageViewCreateInfo* pCreateInfo,
 						   const MVKConfiguration* pAltMVKConfig) : MVKVulkanAPIDeviceObject(device) {
 	_image = (MVKImage*)pCreateInfo->image;
-	_usage = _image ? _image->_usage : 0;
+	_usage = _image->_usage;
 
-	auto* next = (VkStructureType*)pCreateInfo->pNext;
+	auto* next = (MVKVkAPIStructHeader*)pCreateInfo->pNext;
 	while (next) {
-		switch (*next) {
-		case VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO: {
-			auto* pViewUsageInfo = (VkImageViewUsageCreateInfo*)next;
-			if (!(pViewUsageInfo->usage & ~_usage))
-				_usage = pViewUsageInfo->usage;
-			next = (VkStructureType*)pViewUsageInfo->pNext;
-			break;
-		}
-		default:
-			next = (VkStructureType*)((VkImageViewCreateInfo*)next)->pNext;
-			break;
+		switch ((uint32_t)next->sType) {
+			case VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO: {
+				auto* pViewUsageInfo = (VkImageViewUsageCreateInfo*)next;
+				if (!(pViewUsageInfo->usage & ~_usage)) { _usage = pViewUsageInfo->usage; }
+				next = (MVKVkAPIStructHeader*)next->pNext;
+				break;
+			}
+			default:
+				next = (MVKVkAPIStructHeader*)next->pNext;
+				break;
 		}
 	}
 
@@ -942,20 +939,21 @@
 	// Remember the subresource range, and determine the actual number of mip levels and texture slices
     _subresourceRange = pCreateInfo->subresourceRange;
 	if (_subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS) {
-		_subresourceRange.levelCount = _image ? (_image->getMipLevelCount() - _subresourceRange.baseMipLevel) : 1;
+		_subresourceRange.levelCount = _image->getMipLevelCount() - _subresourceRange.baseMipLevel;
 	}
 	if (_subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS) {
-		_subresourceRange.layerCount = _image ? (_image->getLayerCount() - _subresourceRange.baseArrayLayer) : 1;
+		_subresourceRange.layerCount = _image->getLayerCount() - _subresourceRange.baseArrayLayer;
 	}
 
-	bool useSwizzle;
-	bool isMultisample = _image ? _image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT : false;
 	_mtlTexture = nil;
-    _mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useSwizzle,
-												(_device ? _device->_pMVKConfig : pAltMVKConfig));
+	bool useSwizzle;
+	setConfigurationResult(validateSwizzledMTLPixelFormat(pCreateInfo, getPixelFormats(), this,
+														  _device->_pMetalFeatures->nativeTextureSwizzle,
+														  _device->_pMVKConfig->fullImageViewSwizzle,
+														  _mtlPixelFormat, useSwizzle));
 	_packedSwizzle = useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
-	_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, isMultisample);
-
+	_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType,
+														   _image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT);
 	initMTLTextureViewSupport();
 }
 
@@ -982,71 +980,74 @@
 	}
 }
 
-// Returns a MTLPixelFormat, based on the MTLPixelFormat converted from the VkFormat, but possibly
-// modified by the swizzles defined in the VkComponentMapping of the VkImageViewCreateInfo.
-// Metal prior to version 3.0 does not support general per-texture swizzles, so if the swizzle is not an
-// identity swizzle, this function attempts to find an alternate MTLPixelFormat that coincidentally
-// matches the swizzled format.
-// If a replacement MTLFormat was found, it is returned and useSwizzle is set to false.
-// If a replacement MTLFormat could not be found, the original MTLPixelFormat is returned, and the
-// useSwizzle is set to true, indicating that either native or shader swizzling should be used for
-// this image view.
-// The config is used to test whether full shader swizzle support is available, and to report an error if not.
-MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format,
-													   VkComponentMapping components,
-													   bool& useSwizzle,
-													   const MVKConfiguration* pMVKConfig) {
-
-	// Attempt to find a valid format transformation swizzle first.
-	MTLPixelFormat mtlPF = getPixelFormats()->getMTLPixelFormatFromVkFormat(format);
+VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
+													  MVKPixelFormats* mvkPixFmts,
+													  MVKVulkanAPIObject* apiObject,
+													  bool hasNativeSwizzleSupport,
+													  bool hasShaderSwizzleSupport,
+													  MTLPixelFormat& mtlPixFmt,
+													  bool& useSwizzle) {
 	useSwizzle = false;
+	mtlPixFmt = mvkPixFmts->getMTLPixelFormatFromVkFormat(pCreateInfo->format);
+	VkComponentMapping components = pCreateInfo->components;
 
 	#define SWIZZLE_MATCHES(R, G, B, A)    mvkVkComponentMappingsMatch(components, {VK_COMPONENT_SWIZZLE_ ##R, VK_COMPONENT_SWIZZLE_ ##G, VK_COMPONENT_SWIZZLE_ ##B, VK_COMPONENT_SWIZZLE_ ##A} )
 	#define VK_COMPONENT_SWIZZLE_ANY       VK_COMPONENT_SWIZZLE_MAX_ENUM
 
-	switch (mtlPF) {
+	// If we have an identity swizzle, we're all good.
+	if (SWIZZLE_MATCHES(R, G, B, A)) {
+		return VK_SUCCESS;
+	}
+
+	switch (mtlPixFmt) {
 		case MTLPixelFormatR8Unorm:
 			if (SWIZZLE_MATCHES(ZERO, ANY, ANY, R)) {
-				return MTLPixelFormatA8Unorm;
+				mtlPixFmt = MTLPixelFormatA8Unorm;
+				return VK_SUCCESS;
 			}
 			break;
 
 		case MTLPixelFormatA8Unorm:
 			if (SWIZZLE_MATCHES(A, ANY, ANY, ZERO)) {
-				return MTLPixelFormatR8Unorm;
+				mtlPixFmt = MTLPixelFormatR8Unorm;
+				return VK_SUCCESS;
 			}
 			break;
 
 		case MTLPixelFormatRGBA8Unorm:
 			if (SWIZZLE_MATCHES(B, G, R, A)) {
-				return MTLPixelFormatBGRA8Unorm;
+				mtlPixFmt = MTLPixelFormatBGRA8Unorm;
+				return VK_SUCCESS;
 			}
 			break;
 
 		case MTLPixelFormatRGBA8Unorm_sRGB:
 			if (SWIZZLE_MATCHES(B, G, R, A)) {
-				return MTLPixelFormatBGRA8Unorm_sRGB;
+				mtlPixFmt = MTLPixelFormatBGRA8Unorm_sRGB;
+				return VK_SUCCESS;
 			}
 			break;
 
 		case MTLPixelFormatBGRA8Unorm:
 			if (SWIZZLE_MATCHES(B, G, R, A)) {
-				return MTLPixelFormatRGBA8Unorm;
+				mtlPixFmt = MTLPixelFormatRGBA8Unorm;
+				return VK_SUCCESS;
 			}
 			break;
 
 		case MTLPixelFormatBGRA8Unorm_sRGB:
 			if (SWIZZLE_MATCHES(B, G, R, A)) {
-				return MTLPixelFormatRGBA8Unorm_sRGB;
+				mtlPixFmt = MTLPixelFormatRGBA8Unorm_sRGB;
+				return VK_SUCCESS;
 			}
 			break;
 
 		case MTLPixelFormatDepth32Float_Stencil8:
 			// If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed
-			if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
-				mtlPF = MTLPixelFormatX32_Stencil8;
+			if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
+				mtlPixFmt = MTLPixelFormatX32_Stencil8;
 				if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) {
-					return mtlPF;
+					return VK_SUCCESS;
 				}
 			}
 			break;
@@ -1054,10 +1055,10 @@
 #if MVK_MACOS
 		case MTLPixelFormatDepth24Unorm_Stencil8:
 			// If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed
-			if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
-				mtlPF = MTLPixelFormatX24_Stencil8;
+			if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
+				mtlPixFmt = MTLPixelFormatX24_Stencil8;
 				if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) {
-					return mtlPF;
+					return VK_SUCCESS;
 				}
 			}
 			break;
@@ -1067,22 +1068,20 @@
 			break;
 	}
 
-	// No format transformation swizzles were found, so unless we have an identity swizzle, we'll need to use shader swizzling.
-	if ( !SWIZZLE_MATCHES(R, G, B, A)) {
-		useSwizzle = true;
-
-		if ( !pMVKConfig->fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle ) {
-			const char* vkCmd = _image ? "vkCreateImageView(VkImageViewCreateInfo" : "vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDeviceImageViewSupportEXTX";
-			const char* errMsg = ("The value of %s::components) (%s, %s, %s, %s), when applied to a VkImageView, requires full component swizzling to be enabled both at the"
-								  " time when the VkImageView is created and at the time any pipeline that uses that VkImageView is compiled. Full component swizzling can"
-								  " be enabled via the MVKConfiguration::fullImageViewSwizzle config parameter or MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE environment variable.");
-			setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, errMsg, vkCmd,
-											   mvkVkComponentSwizzleName(components.r), mvkVkComponentSwizzleName(components.g),
-											   mvkVkComponentSwizzleName(components.b), mvkVkComponentSwizzleName(components.a)));
-		}
+	// No format transformation swizzles were found, so we'll need to use either native or shader swizzling.
+	useSwizzle = true;
+	if (hasNativeSwizzleSupport || hasShaderSwizzleSupport ) {
+		return VK_SUCCESS;
 	}
 
-	return mtlPF;
+	// Oh, oh. Neither native or shader swizzling is supported.
+	return apiObject->reportError(VK_ERROR_FEATURE_NOT_PRESENT,
+								  "The value of %s::components) (%s, %s, %s, %s), when applied to a VkImageView, requires full component swizzling to be enabled both at the"
+								  " time when the VkImageView is created and at the time any pipeline that uses that VkImageView is compiled. Full component swizzling can"
+								  " be enabled via the MVKConfiguration::fullImageViewSwizzle config parameter or MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE environment variable.",
+								  pCreateInfo->image ? "vkCreateImageView(VkImageViewCreateInfo" : "vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDeviceImageViewSupportEXTX",
+								  mvkVkComponentSwizzleName(components.r), mvkVkComponentSwizzleName(components.g),
+								  mvkVkComponentSwizzleName(components.b), mvkVkComponentSwizzleName(components.a));
 }
 
 // Determine whether this image view should use a Metal texture view,
@@ -1104,7 +1103,7 @@
 		 ((_mtlTextureType == MTLTextureType2D || _mtlTextureType == MTLTextureType2DArray) && is3D)) &&
 		_subresourceRange.levelCount == _image->_mipLevels &&
 		(is3D || _subresourceRange.layerCount == _image->_arrayLayers) &&
-		(!getDevice()->_pMetalFeatures->nativeTextureSwizzle || !_packedSwizzle)) {
+		(!_device->_pMetalFeatures->nativeTextureSwizzle || !_packedSwizzle)) {
 		_useMTLTextureView = false;
 	}
 }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index c7a1aad..cadf19b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -1544,7 +1544,7 @@
 		if (NSSwapLittleIntToHost(hdrComponent) !=  pDevProps->deviceID) { return; }
 
 		reader(pcUUID);			// Pipeline cache UUID
-		if (memcmp(pcUUID, pDevProps->pipelineCacheUUID, VK_UUID_SIZE) != 0) { return; }
+		if (mvkAreEqual(pcUUID, pDevProps->pipelineCacheUUID, VK_UUID_SIZE)) { return; }
 
 		bool done = false;
 		while ( !done ) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
index de13fd0..c01d950 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
@@ -21,13 +21,12 @@
 #include "mvk_datatypes.h"
 #include "MVKEnvironment.h"
 #include "MVKBaseObject.h"
-#include "MVKOSExtensions.h"
 #include <unordered_map>
 
 #import <Metal/Metal.h>
 
 
-/** Validate these values periodically as new formats are added over time. */
+// Validate these values periodically as new formats are added over time.
 static const uint32_t _vkFormatCount = 256;
 static const uint32_t _vkFormatCoreCount = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1;
 static const uint32_t _mtlPixelFormatCount = MTLPixelFormatX32_Stencil8 + 2;     // The actual last enum value is not available on iOS
@@ -35,6 +34,42 @@
 
 
 #pragma mark -
+#pragma mark Metal format capabilities
+
+typedef enum : uint16_t {
+
+	kMVKMTLFmtCapsNone     = 0,
+	kMVKMTLFmtCapsRead     = (1<<0),
+	kMVKMTLFmtCapsFilter   = (1<<1),
+	kMVKMTLFmtCapsWrite    = (1<<2),
+	kMVKMTLFmtCapsColorAtt = (1<<3),
+	kMVKMTLFmtCapsDSAtt    = (1<<4),
+	kMVKMTLFmtCapsBlend    = (1<<5),
+	kMVKMTLFmtCapsMSAA     = (1<<6),
+	kMVKMTLFmtCapsResolve  = (1<<7),
+	kMVKMTLFmtCapsVertex   = (1<<8),
+
+	kMVKMTLFmtCapsRF       = (kMVKMTLFmtCapsRead | kMVKMTLFmtCapsFilter),
+	kMVKMTLFmtCapsRC       = (kMVKMTLFmtCapsRead | kMVKMTLFmtCapsColorAtt),
+	kMVKMTLFmtCapsRCB      = (kMVKMTLFmtCapsRC | kMVKMTLFmtCapsBlend),
+	kMVKMTLFmtCapsRCM      = (kMVKMTLFmtCapsRC | kMVKMTLFmtCapsMSAA),
+	kMVKMTLFmtCapsRCMB     = (kMVKMTLFmtCapsRCM | kMVKMTLFmtCapsBlend),
+	kMVKMTLFmtCapsRWC      = (kMVKMTLFmtCapsRC | kMVKMTLFmtCapsWrite),
+	kMVKMTLFmtCapsRWCB     = (kMVKMTLFmtCapsRWC | kMVKMTLFmtCapsBlend),
+	kMVKMTLFmtCapsRWCM     = (kMVKMTLFmtCapsRWC | kMVKMTLFmtCapsMSAA),
+	kMVKMTLFmtCapsRWCMB    = (kMVKMTLFmtCapsRWCM | kMVKMTLFmtCapsBlend),
+	kMVKMTLFmtCapsRFCMRB   = (kMVKMTLFmtCapsRCMB | kMVKMTLFmtCapsFilter | kMVKMTLFmtCapsResolve),
+	kMVKMTLFmtCapsRFWCMB   = (kMVKMTLFmtCapsRWCMB | kMVKMTLFmtCapsFilter),
+	kMVKMTLFmtCapsAll      = (kMVKMTLFmtCapsRFWCMB | kMVKMTLFmtCapsResolve),
+
+	kMVKMTLFmtCapsDRM      = (kMVKMTLFmtCapsDSAtt | kMVKMTLFmtCapsRead | kMVKMTLFmtCapsMSAA),
+	kMVKMTLFmtCapsDRMR     = (kMVKMTLFmtCapsDRM | kMVKMTLFmtCapsResolve),
+	kMVKMTLFmtCapsDRFMR    = (kMVKMTLFmtCapsDRMR | kMVKMTLFmtCapsFilter),
+
+} MVKMTLFmtCaps;
+
+
+#pragma mark -
 #pragma mark Format descriptors
 
 /** Describes the properties of a VkFormat, including the corresponding Metal pixel and vertex format. */
@@ -52,10 +87,14 @@
 	bool hasReportedSubstitution;
 
 	inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); };
+
 	inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid); };
 	inline bool isSupportedOrSubstitutable() const { return isSupported() || (mtlPixelFormatSubstitute != MTLPixelFormatInvalid); };
+	inline MTLPixelFormat getMTLPixelFormatOrSubstitute() const { return mtlPixelFormat ? mtlPixelFormat : mtlPixelFormatSubstitute; }
+
 	inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid); };
 	inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); };
+	inline MTLVertexFormat getMTLVertexFormatOrSubstitute() const { return mtlVertexFormat ? mtlVertexFormat : mtlVertexFormatSubstitute; }
 } MVKVkFormatDesc;
 
 /** Describes the properties of a MTLPixelFormat or MTLVertexFormat. */
@@ -65,19 +104,10 @@
 		MTLVertexFormat mtlVertexFormat;
 	};
 	VkFormat vkFormat;
-	MVKOSVersion sinceIOSVersion;
-	MVKOSVersion sinceMacOSVersion;
+	MVKMTLFmtCaps mtlFmtCaps;
 	const char* name;
 
-	inline MVKOSVersion sinceOSVersion() const {
-#if MVK_IOS
-		return sinceIOSVersion;
-#endif
-#if MVK_MACOS
-		return sinceMacOSVersion;
-#endif
-	}
-	inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid) && (mvkOSVersion() >= sinceOSVersion()); };
+	inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid) && (mtlFmtCaps != kMVKMTLFmtCapsNone); };
 } MVKMTLFormatDesc;
 
 
@@ -95,6 +125,9 @@
 	/** Returns whether the VkFormat is supported by this implementation. */
 	bool vkFormatIsSupported(VkFormat vkFormat);
 
+	/** Returns whether the VkFormat is supported by this implementation, or can be substituted by one that is. */
+	bool vkFormatIsSupportedOrSubstitutable(VkFormat vkFormat);
+
 	/** Returns whether the MTLPixelFormat is supported by this implementation. */
 	bool mtlPixelFormatIsSupported(MTLPixelFormat mtlFormat);
 
@@ -199,6 +232,12 @@
 	/** Returns the default properties for the specified Vulkan format. */
 	VkFormatProperties getVkFormatProperties(VkFormat vkFormat);
 
+	/** Returns the Metal format capabilities supported by the specified Vulkan format. */
+	MVKMTLFmtCaps getVkFormatCapabilities(VkFormat vkFormat);
+
+	/** Returns the Metal format capabilities supported by the specified Metal format. */
+	MVKMTLFmtCaps getMTLPixelFormatCapabilities(MTLPixelFormat mtlFormat);
+
 	/** Returns the name of the specified Vulkan format. */
 	const char* getVkFormatName(VkFormat vkFormat);
 
@@ -235,23 +274,38 @@
 
 	MVKPixelFormats(MVKVulkanAPIObject* apiObject, id<MTLDevice> mtlDevice);
 
-	MVKPixelFormats() : MVKPixelFormats(nullptr, nil) {}
+	MVKPixelFormats();
 
 protected:
 	MVKVkFormatDesc& getVkFormatDesc(VkFormat vkFormat);
 	MVKVkFormatDesc& getVkFormatDesc(MTLPixelFormat mtlFormat);
+	MVKMTLFormatDesc& getMTLPixelFormatDesc(VkFormat vkFormat);
 	MVKMTLFormatDesc& getMTLPixelFormatDesc(MTLPixelFormat mtlFormat);
+	MVKMTLFormatDesc& getMTLVertexFormatDesc(VkFormat vkFormat);
 	MVKMTLFormatDesc& getMTLVertexFormatDesc(MTLVertexFormat mtlFormat);
+	VkFormatFeatureFlags getOptimalTilingFeatures(MVKMTLFmtCaps mtlFmtCaps);
+	VkFormatFeatureFlags getLinearTilingFeatures(MVKMTLFmtCaps mtlFmtCaps, MVKFormatType mvkFmtType);
+	VkFormatFeatureFlags getBufferFeatures(MVKMTLFmtCaps mtlFmtTexCaps, MVKMTLFmtCaps mtlFmtVtxCaps, MVKFormatType mvkFmtType);
+	void init(id<MTLDevice> mtlDevice);
 	void initVkFormatCapabilities();
 	void initMTLPixelFormatCapabilities();
 	void initMTLVertexFormatCapabilities();
-	void buildFormatMaps();
-	void modifyFormatCapabilitiesForMTLDevice(id<MTLDevice> mtlDevice);
-	void disableMTLPixelFormat(MTLPixelFormat mtlFormat);
+	void buildMTLFormatMaps();
+	void buildVkFormatMaps();
+	void modifyMTLFormatCapabilities(id<MTLDevice> mtlDevice);
+	void addMTLPixelFormatCapabilities(id<MTLDevice> mtlDevice,
+									   MTLFeatureSet mtlFeatSet,
+									   MTLPixelFormat mtlPixFmt,
+									   MVKMTLFmtCaps mtlFmtCaps);
+	void addMTLVertexFormatCapabilities(id<MTLDevice> mtlDevice,
+										MTLFeatureSet mtlFeatSet,
+										MTLVertexFormat mtlVtxFmt,
+										MVKMTLFmtCaps mtlFmtCaps);
 
 	template<typename T>
 	void testFmt(const T v1, const T v2, const char* fmtName, const char* funcName);
-	void test();
+	void testProps(const VkFormatProperties p1, const VkFormatProperties p2, const char* fmtName);
+	void test(id<MTLDevice> mtlDevice);
 
 	MVKVulkanAPIObject* _apiObject;
 	MVKVkFormatDesc _vkFormatDescriptions[_vkFormatCount];
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
index 6723e6b..a8526de 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -16,82 +16,15 @@
  * limitations under the License.
  */
 
-#include "mvk_datatypes.hpp"
 #include "MVKPixelFormats.h"
 #include "MVKVulkanAPIObject.h"
 #include "MVKFoundation.h"
 #include "MVKLogging.h"
 #include <string>
-#include <limits>
 
 using namespace std;
 
 
-#pragma mark -
-#pragma mark Image properties
-
-#define MVK_FMT_IMAGE_FEATS			(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT                    \
-									| VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT                   \
-                                    | VK_FORMAT_FEATURE_BLIT_SRC_BIT                        \
-									| VK_FORMAT_FEATURE_TRANSFER_SRC_BIT                    \
-									| VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
-
-#define MVK_FMT_COLOR_INTEGER_FEATS	(MVK_FMT_IMAGE_FEATS                                    \
-									| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT                \
-									| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT          \
-                                    | VK_FORMAT_FEATURE_BLIT_DST_BIT)
-
-#define MVK_FMT_COLOR_FEATS			(MVK_FMT_COLOR_INTEGER_FEATS | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-
-#if MVK_IOS
-// iOS does not support filtering of float32 values.
-#	define MVK_FMT_COLOR_FLOAT32_FEATS	MVK_FMT_COLOR_INTEGER_FEATS
-#else
-#	define MVK_FMT_COLOR_FLOAT32_FEATS	MVK_FMT_COLOR_FEATS
-#endif
-
-#define MVK_FMT_STENCIL_FEATS		(MVK_FMT_IMAGE_FEATS | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
-
-#if MVK_IOS
-// iOS does not support filtering of depth values.
-#	define MVK_FMT_DEPTH_FEATS		MVK_FMT_STENCIL_FEATS
-#else
-#	define MVK_FMT_DEPTH_FEATS		(MVK_FMT_STENCIL_FEATS | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-#endif
-
-#define MVK_FMT_COMPRESSED_FEATS	(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT                    \
-									| VK_FORMAT_FEATURE_TRANSFER_SRC_BIT                    \
-									| VK_FORMAT_FEATURE_TRANSFER_DST_BIT                    \
-									| VK_FORMAT_FEATURE_BLIT_SRC_BIT                        \
-									| VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-
-#if MVK_MACOS
-// macOS does not support linear images as framebuffer attachments.
-#define MVK_FMT_LINEAR_TILING_FEATS	(MVK_FMT_IMAGE_FEATS | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-
-// macOS also does not support E5B9G9R9 for anything but filtering.
-#define MVK_FMT_E5B9G9R9_FEATS 		MVK_FMT_COMPRESSED_FEATS
-#else
-#define MVK_FMT_LINEAR_TILING_FEATS	MVK_FMT_COLOR_FEATS
-#define MVK_FMT_E5B9G9R9_FEATS		MVK_FMT_COLOR_FEATS
-#endif
-
-#define MVK_FMT_BUFFER_FEATS		(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT             \
-									| VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
-
-#define MVK_FMT_BUFFER_VTX_FEATS	(MVK_FMT_BUFFER_FEATS | VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
-
-#define MVK_FMT_BUFFER_RDONLY_FEATS	(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)
-
-#if MVK_MACOS
-#define MVK_FMT_E5B9G9R9_BUFFER_FEATS 		MVK_FMT_BUFFER_RDONLY_FEATS
-#else
-#define MVK_FMT_E5B9G9R9_BUFFER_FEATS 		MVK_FMT_BUFFER_FEATS
-#endif
-
-#define MVK_FMT_NO_FEATS			0
-
-
 // Add stub defs for unsupported MTLPixelFormats per platform
 #if MVK_MACOS
 #   define MTLPixelFormatABGR4Unorm             MTLPixelFormatInvalid
@@ -151,11 +84,16 @@
 #   define MTLPixelFormatPVRTC_RGBA_4BPP_sRGB   MTLPixelFormatInvalid
 
 #   define MTLPixelFormatDepth16Unorm_Stencil8  MTLPixelFormatDepth24Unorm_Stencil8
+#   define MTLPixelFormatBGRA10_XR				MTLPixelFormatInvalid
+#   define MTLPixelFormatBGRA10_XR_sRGB			MTLPixelFormatInvalid
+#   define MTLPixelFormatBGR10_XR				MTLPixelFormatInvalid
+#   define MTLPixelFormatBGR10_XR_sRGB			MTLPixelFormatInvalid
 #endif
 
 #if MVK_IOS
 #   define MTLPixelFormatDepth16Unorm           MTLPixelFormatInvalid
 #   define MTLPixelFormatDepth24Unorm_Stencil8  MTLPixelFormatInvalid
+#   define MTLPixelFormatX24_Stencil8           MTLPixelFormatInvalid
 #   define MTLPixelFormatBC1_RGBA               MTLPixelFormatInvalid
 #   define MTLPixelFormatBC1_RGBA_sRGB          MTLPixelFormatInvalid
 #   define MTLPixelFormatBC2_RGBA               MTLPixelFormatInvalid
@@ -182,6 +120,10 @@
 	return getVkFormatDesc(vkFormat).isSupported();
 }
 
+bool MVKPixelFormats::vkFormatIsSupportedOrSubstitutable(VkFormat vkFormat) {
+	return getVkFormatDesc(vkFormat).isSupportedOrSubstitutable();
+}
+
 bool MVKPixelFormats::mtlPixelFormatIsSupported(MTLPixelFormat mtlFormat) {
 	return getMTLPixelFormatDesc(mtlFormat).isSupported();
 }
@@ -242,13 +184,12 @@
 }
 
 MTLPixelFormat MVKPixelFormats::getMTLPixelFormatFromVkFormat(VkFormat vkFormat) {
-	MTLPixelFormat mtlPixFmt = MTLPixelFormatInvalid;
-
 	auto& vkDesc = getVkFormatDesc(vkFormat);
-	if (vkDesc.isSupported()) {
-		mtlPixFmt = vkDesc.mtlPixelFormat;
-	} else if (vkFormat != VK_FORMAT_UNDEFINED) {
-		// If the MTLPixelFormat is not supported but VkFormat is valid, attempt to substitute a different format.
+	MTLPixelFormat mtlPixFmt = vkDesc.mtlPixelFormat;
+
+	// If the MTLPixelFormat is not supported but VkFormat is valid,
+	// attempt to substitute a different format and potentially report an error.
+	if ( !mtlPixFmt && vkFormat ) {
 		mtlPixFmt = vkDesc.mtlPixelFormatSubstitute;
 
 		// Report an error if there is no substitute, or the first time a substitution is made.
@@ -320,19 +261,15 @@
 }
 
 VkFormatProperties MVKPixelFormats::getVkFormatProperties(VkFormat vkFormat) {
-	VkFormatProperties fmtProps = {MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS};
-	auto& vkDesc = getVkFormatDesc(vkFormat);
-	if (vkDesc.isSupported()) {
-		fmtProps = vkDesc.properties;
-		if ( !vkDesc.vertexIsSupportedOrSubstitutable() ) {
-			// If vertex format is not supported, disable vertex buffer bit
-			fmtProps.bufferFeatures &= ~VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
-		}
-	} else {
-		// If texture format is unsupported, vertex buffer format may still be.
-		fmtProps.bufferFeatures |= vkDesc.properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
-	}
-	return fmtProps;
+	return	getVkFormatDesc(vkFormat).properties;
+}
+
+MVKMTLFmtCaps MVKPixelFormats::getVkFormatCapabilities(VkFormat vkFormat) {
+	return getMTLPixelFormatDesc(vkFormat).mtlFmtCaps;
+}
+
+MVKMTLFmtCaps MVKPixelFormats::getMTLPixelFormatCapabilities(MTLPixelFormat mtlFormat) {
+	return getMTLPixelFormatDesc(mtlFormat).mtlFmtCaps;
 }
 
 const char* MVKPixelFormats::getVkFormatName(VkFormat vkFormat) {
@@ -364,14 +301,12 @@
 }
 
 MTLVertexFormat MVKPixelFormats::getMTLVertexFormatFromVkFormat(VkFormat vkFormat) {
-	MTLVertexFormat mtlVtxFmt = MTLVertexFormatInvalid;
-
 	auto& vkDesc = getVkFormatDesc(vkFormat);
-	if (vkDesc.vertexIsSupported()) {
-		mtlVtxFmt = vkDesc.mtlVertexFormat;
-	} else if (vkFormat != VK_FORMAT_UNDEFINED) {
-		// If the MTLVertexFormat is not supported but VkFormat is valid,
-		// report an error, and possibly substitute a different MTLVertexFormat.
+	MTLVertexFormat mtlVtxFmt = vkDesc.mtlVertexFormat;
+
+	// If the MTLVertexFormat is not supported but VkFormat is valid,
+	// report an error, and possibly substitute a different MTLVertexFormat.
+	if ( !mtlVtxFmt && vkFormat ) {
 		string errMsg;
 		errMsg += "VkFormat ";
 		errMsg += (vkDesc.name) ? vkDesc.name : to_string(vkDesc.vkFormat);
@@ -437,24 +372,24 @@
 }
 
 VkImageUsageFlags MVKPixelFormats::getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsage mtlUsage,
-																	  MTLPixelFormat mtlFormat) {
+																		   MTLPixelFormat mtlFormat) {
     VkImageUsageFlags vkImageUsageFlags = 0;
 
     if ( mvkAreAllFlagsEnabled(mtlUsage, MTLTextureUsageShaderRead) ) {
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_SAMPLED_BIT);
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
+        mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+        mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_SAMPLED_BIT);
+        mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
     }
     if ( mvkAreAllFlagsEnabled(mtlUsage, MTLTextureUsageRenderTarget) ) {
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_TRANSFER_DST_BIT);
+        mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_TRANSFER_DST_BIT);
         if (mtlPixelFormatIsDepthFormat(mtlFormat) || mtlPixelFormatIsStencilFormat(mtlFormat)) {
-            mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+            mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
         } else {
-            mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
+            mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
         }
     }
     if ( mvkAreAllFlagsEnabled(mtlUsage, MTLTextureUsageShaderWrite) ) {
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_STORAGE_BIT);
+        mvkEnableFlags(vkImageUsageFlags, VK_IMAGE_USAGE_STORAGE_BIT);
     }
 
     return vkImageUsageFlags;
@@ -466,40 +401,66 @@
 	return _vkFormatDescriptions[fmtIdx];
 }
 
+// Return a reference to the Vulkan format descriptor corresponding to the MTLPixelFormat.
+MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(MTLPixelFormat mtlFormat) {
+	return getVkFormatDesc(getMTLPixelFormatDesc(mtlFormat).vkFormat);
+}
+
+// Return a reference to the Metal format descriptor corresponding to the VkFormat.
+MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(VkFormat vkFormat) {
+	return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).getMTLPixelFormatOrSubstitute());
+}
+
 // Return a reference to the Metal format descriptor corresponding to the MTLPixelFormat.
 MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(MTLPixelFormat mtlFormat) {
 	uint16_t fmtIdx = (mtlFormat < _mtlPixelFormatCount) ? _mtlFormatDescIndicesByMTLPixelFormats[mtlFormat] : 0;
 	return _mtlPixelFormatDescriptions[fmtIdx];
 }
 
+// Return a reference to the Metal format descriptor corresponding to the VkFormat.
+MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(VkFormat vkFormat) {
+	return getMTLVertexFormatDesc(getVkFormatDesc(vkFormat).getMTLVertexFormatOrSubstitute());
+}
+
 // Return a reference to the Metal format descriptor corresponding to the MTLVertexFormat.
 MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(MTLVertexFormat mtlFormat) {
 	uint16_t fmtIdx = (mtlFormat < _mtlVertexFormatCount) ? _mtlFormatDescIndicesByMTLVertexFormats[mtlFormat] : 0;
 	return _mtlVertexFormatDescriptions[fmtIdx];
 }
 
-// Return a reference to the Vulkan format descriptor corresponding to the MTLPixelFormat.
-MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(MTLPixelFormat mtlFormat) {
-	return getVkFormatDesc(getMTLPixelFormatDesc(mtlFormat).vkFormat);
-}
-
 
 #pragma mark Construction
 
 MVKPixelFormats::MVKPixelFormats(MVKVulkanAPIObject* apiObject, id<MTLDevice> mtlDevice) : _apiObject(apiObject) {
-	initVkFormatCapabilities();
-	initMTLPixelFormatCapabilities();
-	initMTLVertexFormatCapabilities();
-	buildFormatMaps();
-	modifyFormatCapabilitiesForMTLDevice(mtlDevice);
-//	test();
+	init(mtlDevice);
 }
 
-static const MVKOSVersion kMTLFmtNA = numeric_limits<MVKOSVersion>::max();
+//	Retrieves the default MTLDevice, which needs to be released after use.
+MVKPixelFormats::MVKPixelFormats() : _apiObject(nullptr) {
+	id<MTLDevice> mtlDevice = MTLCreateSystemDefaultDevice();	// retained
+	init(mtlDevice);
+	[mtlDevice release];	// Release temp instance
+}
 
-#define MVK_ADD_VKFMT_STRUCT(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE, PIXEL_FEATS, BUFFER_FEATS)  \
-	MVKAssert(fmtIdx < _vkFormatCount, "Attempting to describe %d VkFormats, but only have space for %d. Increase the value of _vkFormatCount", fmtIdx + 1, _vkFormatCount);		\
-	_vkFormatDescriptions[fmtIdx++] = { VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, { BLK_W, BLK_H }, BLK_BYTE_CNT, MVK_FMT_TYPE, { (PIXEL_FEATS & MVK_FMT_LINEAR_TILING_FEATS), PIXEL_FEATS, BUFFER_FEATS }, #VK_FMT, false }
+void MVKPixelFormats::init(id<MTLDevice> mtlDevice) {
+
+	// Build and update the Metal formats
+	initMTLPixelFormatCapabilities();
+	initMTLVertexFormatCapabilities();
+	buildMTLFormatMaps();
+	modifyMTLFormatCapabilities(mtlDevice);
+
+	// Build the Vulkan formats and link them to the Metal formats
+	initVkFormatCapabilities();
+	buildVkFormatMaps();
+
+//	test(mtlDevice);
+}
+
+#define addVkFormatDesc(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE)  \
+	MVKAssert(fmtIdx < _vkFormatCount, "Attempting to describe %d VkFormats, but only have space for %d. Increase the value of _vkFormatCount", fmtIdx + 1, _vkFormatCount);  \
+	_vkFormatDescriptions[fmtIdx++] = { VK_FORMAT_ ##VK_FMT, MTLPixelFormat ##MTL_FMT, MTLPixelFormat ##MTL_FMT_ALT, MTLVertexFormat ##MTL_VTX_FMT, MTLVertexFormat ##MTL_VTX_FMT_ALT,  \
+										{ BLK_W, BLK_H }, BLK_BYTE_CNT, kMVKFormat ##MVK_FMT_TYPE, { 0, 0, 0 }, "VK_FORMAT_" #VK_FMT, false }
 
 void MVKPixelFormats::initVkFormatCapabilities() {
 
@@ -508,253 +469,255 @@
 	uint32_t fmtIdx = 0;
 
 	// When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count
-	// VK_FORMAT_UNDEFINED must come first.
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_UNDEFINED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 0, kMVKFormatNone, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	// UNDEFINED must come first.
+	addVkFormatDesc( UNDEFINED, Invalid, Invalid, Invalid, Invalid, 1, 1, 0, None );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R4G4_UNORM_PACK8, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 1, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R4G4B4A4_UNORM_PACK16, MTLPixelFormatABGR4Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );	// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B4G4R4A4_UNORM_PACK16, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( R4G4_UNORM_PACK8, Invalid, Invalid, Invalid, Invalid, 1, 1, 1, ColorFloat );
+	addVkFormatDesc( R4G4B4A4_UNORM_PACK16, ABGR4Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( B4G4R4A4_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R5G6B5_UNORM_PACK16, MTLPixelFormatB5G6R5Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );	// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B5G6R5_UNORM_PACK16, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R5G5B5A1_UNORM_PACK16, MTLPixelFormatA1BGR5Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );	// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B5G5R5A1_UNORM_PACK16, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A1R5G5B5_UNORM_PACK16, MTLPixelFormatBGR5A1Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );	// Vulkan packed is reversed
+	addVkFormatDesc( R5G6B5_UNORM_PACK16, B5G6R5Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( B5G6R5_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R5G5B5A1_UNORM_PACK16, A1BGR5Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( B5G5R5A1_UNORM_PACK16, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( A1R5G5B5_UNORM_PACK16, BGR5A1Unorm, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_UNORM, MTLPixelFormatR8Unorm, MTLPixelFormatInvalid, MTLVertexFormatUCharNormalized, MTLVertexFormatUChar2Normalized, 1, 1, 1, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_SNORM, MTLPixelFormatR8Snorm, MTLPixelFormatInvalid, MTLVertexFormatCharNormalized, MTLVertexFormatChar2Normalized, 1, 1, 1, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 1, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 1, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_UINT, MTLPixelFormatR8Uint, MTLPixelFormatInvalid, MTLVertexFormatUChar, MTLVertexFormatUChar2, 1, 1, 1, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_SINT, MTLPixelFormatR8Sint, MTLPixelFormatInvalid, MTLVertexFormatChar, MTLVertexFormatChar2, 1, 1, 1, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8_SRGB, MTLPixelFormatR8Unorm_sRGB, MTLPixelFormatInvalid, MTLVertexFormatUCharNormalized, MTLVertexFormatUChar2Normalized, 1, 1, 1, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( R8_UNORM, R8Unorm, Invalid, UCharNormalized, UChar2Normalized, 1, 1, 1, ColorFloat );
+	addVkFormatDesc( R8_SNORM, R8Snorm, Invalid, CharNormalized, Char2Normalized, 1, 1, 1, ColorFloat );
+	addVkFormatDesc( R8_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 1, ColorFloat );
+	addVkFormatDesc( R8_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 1, ColorFloat );
+	addVkFormatDesc( R8_UINT, R8Uint, Invalid, UChar, UChar2, 1, 1, 1, ColorUInt8 );
+	addVkFormatDesc( R8_SINT, R8Sint, Invalid, Char, Char2, 1, 1, 1, ColorInt8 );
+	addVkFormatDesc( R8_SRGB, R8Unorm_sRGB, Invalid, UCharNormalized, UChar2Normalized, 1, 1, 1, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_UNORM, MTLPixelFormatRG8Unorm, MTLPixelFormatInvalid, MTLVertexFormatUChar2Normalized, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_SNORM, MTLPixelFormatRG8Snorm, MTLPixelFormatInvalid, MTLVertexFormatChar2Normalized, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_UINT, MTLPixelFormatRG8Uint, MTLPixelFormatInvalid, MTLVertexFormatUChar2, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_SINT, MTLPixelFormatRG8Sint, MTLPixelFormatInvalid, MTLVertexFormatChar2, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8_SRGB, MTLPixelFormatRG8Unorm_sRGB, MTLPixelFormatInvalid, MTLVertexFormatUChar2Normalized, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( R8G8_UNORM, RG8Unorm, Invalid, UChar2Normalized, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R8G8_SNORM, RG8Snorm, Invalid, Char2Normalized, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R8G8_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R8G8_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R8G8_UINT, RG8Uint, Invalid, UChar2, Invalid, 1, 1, 2, ColorUInt8 );
+	addVkFormatDesc( R8G8_SINT, RG8Sint, Invalid, Char2, Invalid, 1, 1, 2, ColorInt8 );
+	addVkFormatDesc( R8G8_SRGB, RG8Unorm_sRGB, Invalid, UChar2Normalized, Invalid, 1, 1, 2, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_UNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatUChar3Normalized, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatChar3Normalized, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatUChar3, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatChar3, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8_SRGB, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatUChar3Normalized, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( R8G8B8_UNORM, Invalid, Invalid, UChar3Normalized, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( R8G8B8_SNORM, Invalid, Invalid, Char3Normalized, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( R8G8B8_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( R8G8B8_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( R8G8B8_UINT, Invalid, Invalid, UChar3, Invalid, 1, 1, 3, ColorUInt8 );
+	addVkFormatDesc( R8G8B8_SINT, Invalid, Invalid, Char3, Invalid, 1, 1, 3, ColorInt8 );
+	addVkFormatDesc( R8G8B8_SRGB, Invalid, Invalid, UChar3Normalized, Invalid, 1, 1, 3, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_UNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorUInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8_SRGB, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( B8G8R8_UNORM, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( B8G8R8_SNORM, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( B8G8R8_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( B8G8R8_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
+	addVkFormatDesc( B8G8R8_UINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorUInt8 );
+	addVkFormatDesc( B8G8R8_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorInt8 );
+	addVkFormatDesc( B8G8R8_SRGB, Invalid, Invalid, Invalid, Invalid, 1, 1, 3, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_UNORM, MTLPixelFormatRGBA8Unorm, MTLPixelFormatInvalid, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_SNORM, MTLPixelFormatRGBA8Snorm, MTLPixelFormatInvalid, MTLVertexFormatChar4Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_UINT, MTLPixelFormatRGBA8Uint, MTLPixelFormatInvalid, MTLVertexFormatUChar4, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_SINT, MTLPixelFormatRGBA8Sint, MTLPixelFormatInvalid, MTLVertexFormatChar4, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R8G8B8A8_SRGB, MTLPixelFormatRGBA8Unorm_sRGB, MTLPixelFormatInvalid, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( R8G8B8A8_UNORM, RGBA8Unorm, Invalid, UChar4Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R8G8B8A8_SNORM, RGBA8Snorm, Invalid, Char4Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R8G8B8A8_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R8G8B8A8_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R8G8B8A8_UINT, RGBA8Uint, Invalid, UChar4, Invalid, 1, 1, 4, ColorUInt8 );
+	addVkFormatDesc( R8G8B8A8_SINT, RGBA8Sint, Invalid, Char4, Invalid, 1, 1, 4, ColorInt8 );
+	addVkFormatDesc( R8G8B8A8_SRGB, RGBA8Unorm_sRGB, Invalid, UChar4Normalized, Invalid, 1, 1, 4, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_UNORM, MTLPixelFormatBGRA8Unorm, MTLPixelFormatInvalid, MTLVertexFormatUChar4Normalized_BGRA, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B8G8R8A8_SRGB, MTLPixelFormatBGRA8Unorm_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( B8G8R8A8_UNORM, BGRA8Unorm, Invalid, UChar4Normalized_BGRA, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( B8G8R8A8_SNORM, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( B8G8R8A8_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( B8G8R8A8_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( B8G8R8A8_UINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorUInt8 );
+	addVkFormatDesc( B8G8R8A8_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorInt8 );
+	addVkFormatDesc( B8G8R8A8_SRGB, BGRA8Unorm_sRGB, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_UNORM_PACK32, MTLPixelFormatRGBA8Unorm, MTLPixelFormatInvalid, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_SNORM_PACK32, MTLPixelFormatRGBA8Snorm, MTLPixelFormatInvalid, MTLVertexFormatChar4Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_USCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_SSCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_UINT_PACK32, MTLPixelFormatRGBA8Uint, MTLPixelFormatInvalid, MTLVertexFormatUChar4, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_SINT_PACK32, MTLPixelFormatRGBA8Sint, MTLPixelFormatInvalid, MTLVertexFormatChar4, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A8B8G8R8_SRGB_PACK32, MTLPixelFormatRGBA8Unorm_sRGB, MTLPixelFormatInvalid, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( A8B8G8R8_UNORM_PACK32, RGBA8Unorm, Invalid, UChar4Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A8B8G8R8_SNORM_PACK32, RGBA8Snorm, Invalid, Char4Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A8B8G8R8_USCALED_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A8B8G8R8_SSCALED_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A8B8G8R8_UINT_PACK32, RGBA8Uint, Invalid, UChar4, Invalid, 1, 1, 4, ColorUInt8 );
+	addVkFormatDesc( A8B8G8R8_SINT_PACK32, RGBA8Sint, Invalid, Char4, Invalid, 1, 1, 4, ColorInt8 );
+	addVkFormatDesc( A8B8G8R8_SRGB_PACK32, RGBA8Unorm_sRGB, Invalid, UChar4Normalized, Invalid, 1, 1, 4, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2R10G10B10_UNORM_PACK32, MTLPixelFormatBGR10A2Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );	// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2R10G10B10_SNORM_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2R10G10B10_USCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2R10G10B10_SSCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2R10G10B10_UINT_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt16, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2R10G10B10_SINT_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt16, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( A2R10G10B10_UNORM_PACK32, BGR10A2Unorm, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2R10G10B10_SNORM_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2R10G10B10_USCALED_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2R10G10B10_SSCALED_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2R10G10B10_UINT_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorUInt16 );
+	addVkFormatDesc( A2R10G10B10_SINT_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorInt16 );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2B10G10R10_UNORM_PACK32, MTLPixelFormatRGB10A2Unorm, MTLPixelFormatInvalid, MTLVertexFormatUInt1010102Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );	// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2B10G10R10_SNORM_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInt1010102Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2B10G10R10_USCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2B10G10R10_SSCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2B10G10R10_UINT_PACK32, MTLPixelFormatRGB10A2Uint, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_FEATS );		// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_A2B10G10R10_SINT_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt16, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( A2B10G10R10_UNORM_PACK32, RGB10A2Unorm, Invalid, UInt1010102Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2B10G10R10_SNORM_PACK32, Invalid, Invalid, Int1010102Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2B10G10R10_USCALED_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2B10G10R10_SSCALED_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( A2B10G10R10_UINT_PACK32, RGB10A2Uint, Invalid, Invalid, Invalid, 1, 1, 4, ColorUInt16 );
+	addVkFormatDesc( A2B10G10R10_SINT_PACK32, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorInt16 );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_UNORM, MTLPixelFormatR16Unorm, MTLPixelFormatInvalid, MTLVertexFormatUShortNormalized, MTLVertexFormatUShort2Normalized, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_SNORM, MTLPixelFormatR16Snorm, MTLPixelFormatInvalid, MTLVertexFormatShortNormalized, MTLVertexFormatShort2Normalized, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_UINT, MTLPixelFormatR16Uint, MTLPixelFormatInvalid, MTLVertexFormatUShort, MTLVertexFormatUShort2, 1, 1, 2, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_SINT, MTLPixelFormatR16Sint, MTLPixelFormatInvalid, MTLVertexFormatShort, MTLVertexFormatShort2, 1, 1, 2, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16_SFLOAT, MTLPixelFormatR16Float, MTLPixelFormatInvalid, MTLVertexFormatHalf, MTLVertexFormatHalf2, 1, 1, 2, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R16_UNORM, R16Unorm, Invalid, UShortNormalized, UShort2Normalized, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R16_SNORM, R16Snorm, Invalid, ShortNormalized, Short2Normalized, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R16_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R16_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 2, ColorFloat );
+	addVkFormatDesc( R16_UINT, R16Uint, Invalid, UShort, UShort2, 1, 1, 2, ColorUInt16 );
+	addVkFormatDesc( R16_SINT, R16Sint, Invalid, Short, Short2, 1, 1, 2, ColorInt16 );
+	addVkFormatDesc( R16_SFLOAT, R16Float, Invalid, Half, Half2, 1, 1, 2, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_UNORM, MTLPixelFormatRG16Unorm, MTLPixelFormatInvalid, MTLVertexFormatUShort2Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_SNORM, MTLPixelFormatRG16Snorm, MTLPixelFormatInvalid, MTLVertexFormatShort2Normalized, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_UINT, MTLPixelFormatRG16Uint, MTLPixelFormatInvalid, MTLVertexFormatUShort2, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_SINT, MTLPixelFormatRG16Sint, MTLPixelFormatInvalid, MTLVertexFormatShort2, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16_SFLOAT, MTLPixelFormatRG16Float, MTLPixelFormatInvalid, MTLVertexFormatHalf2, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R16G16_UNORM, RG16Unorm, Invalid, UShort2Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R16G16_SNORM, RG16Snorm, Invalid, Short2Normalized, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R16G16_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R16G16_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( R16G16_UINT, RG16Uint, Invalid, UShort2, Invalid, 1, 1, 4, ColorUInt16 );
+	addVkFormatDesc( R16G16_SINT, RG16Sint, Invalid, Short2, Invalid, 1, 1, 4, ColorInt16 );
+	addVkFormatDesc( R16G16_SFLOAT, RG16Float, Invalid, Half2, Invalid, 1, 1, 4, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_UNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatUShort3Normalized, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatShort3Normalized, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatUShort3, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatShort3, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatHalf3, MTLVertexFormatInvalid, 1, 1, 6, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R16G16B16_UNORM, Invalid, Invalid, UShort3Normalized, Invalid, 1, 1, 6, ColorFloat );
+	addVkFormatDesc( R16G16B16_SNORM, Invalid, Invalid, Short3Normalized, Invalid, 1, 1, 6, ColorFloat );
+	addVkFormatDesc( R16G16B16_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 6, ColorFloat );
+	addVkFormatDesc( R16G16B16_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 6, ColorFloat );
+	addVkFormatDesc( R16G16B16_UINT, Invalid, Invalid, UShort3, Invalid, 1, 1, 6, ColorUInt16 );
+	addVkFormatDesc( R16G16B16_SINT, Invalid, Invalid, Short3, Invalid, 1, 1, 6, ColorInt16 );
+	addVkFormatDesc( R16G16B16_SFLOAT, Invalid, Invalid, Half3, Invalid, 1, 1, 6, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_UNORM, MTLPixelFormatRGBA16Unorm, MTLPixelFormatInvalid, MTLVertexFormatUShort4Normalized, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_SNORM, MTLPixelFormatRGBA16Snorm, MTLPixelFormatInvalid, MTLVertexFormatShort4Normalized, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_UINT, MTLPixelFormatRGBA16Uint, MTLPixelFormatInvalid, MTLVertexFormatUShort4, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_SINT, MTLPixelFormatRGBA16Sint, MTLPixelFormatInvalid, MTLVertexFormatShort4, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R16G16B16A16_SFLOAT, MTLPixelFormatRGBA16Float, MTLPixelFormatInvalid, MTLVertexFormatHalf4, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R16G16B16A16_UNORM, RGBA16Unorm, Invalid, UShort4Normalized, Invalid, 1, 1, 8, ColorFloat );
+	addVkFormatDesc( R16G16B16A16_SNORM, RGBA16Snorm, Invalid, Short4Normalized, Invalid, 1, 1, 8, ColorFloat );
+	addVkFormatDesc( R16G16B16A16_USCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 8, ColorFloat );
+	addVkFormatDesc( R16G16B16A16_SSCALED, Invalid, Invalid, Invalid, Invalid, 1, 1, 8, ColorFloat );
+	addVkFormatDesc( R16G16B16A16_UINT, RGBA16Uint, Invalid, UShort4, Invalid, 1, 1, 8, ColorUInt16 );
+	addVkFormatDesc( R16G16B16A16_SINT, RGBA16Sint, Invalid, Short4, Invalid, 1, 1, 8, ColorInt16 );
+	addVkFormatDesc( R16G16B16A16_SFLOAT, RGBA16Float, Invalid, Half4, Invalid, 1, 1, 8, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32_UINT, MTLPixelFormatR32Uint, MTLPixelFormatInvalid, MTLVertexFormatUInt, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32_SINT, MTLPixelFormatR32Sint, MTLPixelFormatInvalid, MTLVertexFormatInt, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32_SFLOAT, MTLPixelFormatR32Float, MTLPixelFormatInvalid, MTLVertexFormatFloat, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R32_UINT, R32Uint, Invalid, UInt, Invalid, 1, 1, 4, ColorUInt32 );
+	addVkFormatDesc( R32_SINT, R32Sint, Invalid, Int, Invalid, 1, 1, 4, ColorInt32 );
+	addVkFormatDesc( R32_SFLOAT, R32Float, Invalid, Float, Invalid, 1, 1, 4, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32_UINT, MTLPixelFormatRG32Uint, MTLPixelFormatInvalid, MTLVertexFormatUInt2, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32_SINT, MTLPixelFormatRG32Sint, MTLPixelFormatInvalid, MTLVertexFormatInt2, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32_SFLOAT, MTLPixelFormatRG32Float, MTLPixelFormatInvalid, MTLVertexFormatFloat2, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R32G32_UINT, RG32Uint, Invalid, UInt2, Invalid, 1, 1, 8, ColorUInt32 );
+	addVkFormatDesc( R32G32_SINT, RG32Sint, Invalid, Int2, Invalid, 1, 1, 8, ColorInt32 );
+	addVkFormatDesc( R32G32_SFLOAT, RG32Float, Invalid, Float2, Invalid, 1, 1, 8, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32B32_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatUInt3, MTLVertexFormatInvalid, 1, 1, 12, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32B32_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInt3, MTLVertexFormatInvalid, 1, 1, 12, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32B32_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatFloat3, MTLVertexFormatInvalid, 1, 1, 12, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R32G32B32_UINT, Invalid, Invalid, UInt3, Invalid, 1, 1, 12, ColorUInt32 );
+	addVkFormatDesc( R32G32B32_SINT, Invalid, Invalid, Int3, Invalid, 1, 1, 12, ColorInt32 );
+	addVkFormatDesc( R32G32B32_SFLOAT, Invalid, Invalid, Float3, Invalid, 1, 1, 12, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32B32A32_UINT, MTLPixelFormatRGBA32Uint, MTLPixelFormatInvalid, MTLVertexFormatUInt4, MTLVertexFormatInvalid, 1, 1, 16, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32B32A32_SINT, MTLPixelFormatRGBA32Sint, MTLPixelFormatInvalid, MTLVertexFormatInt4, MTLVertexFormatInvalid, 1, 1, 16, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R32G32B32A32_SFLOAT, MTLPixelFormatRGBA32Float, MTLPixelFormatInvalid, MTLVertexFormatFloat4, MTLVertexFormatInvalid, 1, 1, 16, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS );
+	addVkFormatDesc( R32G32B32A32_UINT, RGBA32Uint, Invalid, UInt4, Invalid, 1, 1, 16, ColorUInt32 );
+	addVkFormatDesc( R32G32B32A32_SINT, RGBA32Sint, Invalid, Int4, Invalid, 1, 1, 16, ColorInt32 );
+	addVkFormatDesc( R32G32B32A32_SFLOAT, RGBA32Float, Invalid, Float4, Invalid, 1, 1, 16, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 8, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( R64_UINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 8, ColorFloat );
+	addVkFormatDesc( R64_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 8, ColorFloat );
+	addVkFormatDesc( R64_SFLOAT, Invalid, Invalid, Invalid, Invalid, 1, 1, 8, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 16, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 16, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 16, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( R64G64_UINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 16, ColorFloat );
+	addVkFormatDesc( R64G64_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 16, ColorFloat );
+	addVkFormatDesc( R64G64_SFLOAT, Invalid, Invalid, Invalid, Invalid, 1, 1, 16, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64B64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 24, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64B64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 24, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64B64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 24, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( R64G64B64_UINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 24, ColorFloat );
+	addVkFormatDesc( R64G64B64_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 24, ColorFloat );
+	addVkFormatDesc( R64G64B64_SFLOAT, Invalid, Invalid, Invalid, Invalid, 1, 1, 24, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64B64A64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 32, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64B64A64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 32, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_R64G64B64A64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 32, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( R64G64B64A64_UINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 32, ColorFloat );
+	addVkFormatDesc( R64G64B64A64_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 32, ColorFloat );
+	addVkFormatDesc( R64G64B64A64_SFLOAT, Invalid, Invalid, Invalid, Invalid, 1, 1, 32, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_B10G11R11_UFLOAT_PACK32, MTLPixelFormatRG11B10Float, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );	// Vulkan packed is reversed
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, MTLPixelFormatRGB9E5Float, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatColorFloat, MVK_FMT_E5B9G9R9_FEATS, MVK_FMT_E5B9G9R9_BUFFER_FEATS );	// Vulkan packed is reversed
+	addVkFormatDesc( B10G11R11_UFLOAT_PACK32, RG11B10Float, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
+	addVkFormatDesc( E5B9G9R9_UFLOAT_PACK32, RGB9E5Float, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_D32_SFLOAT, MTLPixelFormatDepth32Float, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_D32_SFLOAT_S8_UINT, MTLPixelFormatDepth32Float_Stencil8, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 5, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( D32_SFLOAT, Depth32Float, Invalid, Invalid, Invalid, 1, 1, 4, DepthStencil );
+	addVkFormatDesc( D32_SFLOAT_S8_UINT, Depth32Float_Stencil8, Invalid, Invalid, Invalid, 1, 1, 5, DepthStencil );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_S8_UINT, MTLPixelFormatStencil8, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 1, kMVKFormatDepthStencil, MVK_FMT_STENCIL_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( S8_UINT, Stencil8, Invalid, Invalid, Invalid, 1, 1, 1, DepthStencil );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_D16_UNORM, MTLPixelFormatDepth16Unorm, MTLPixelFormatDepth32Float, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 2, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_D16_UNORM_S8_UINT, MTLPixelFormatInvalid, MTLPixelFormatDepth16Unorm_Stencil8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 3, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_D24_UNORM_S8_UINT, MTLPixelFormatDepth24Unorm_Stencil8, MTLPixelFormatDepth32Float_Stencil8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( D16_UNORM, Depth16Unorm, Depth32Float, Invalid, Invalid, 1, 1, 2, DepthStencil );
+	addVkFormatDesc( D16_UNORM_S8_UINT, Invalid, Depth16Unorm_Stencil8, Invalid, Invalid, 1, 1, 3, DepthStencil );
+	addVkFormatDesc( D24_UNORM_S8_UINT, Depth24Unorm_Stencil8, Depth32Float_Stencil8, Invalid, Invalid, 1, 1, 4, DepthStencil );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_X8_D24_UNORM_PACK32, MTLPixelFormatInvalid, MTLPixelFormatDepth24Unorm_Stencil8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 1, 1, 4, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS );	// Vulkan packed is reversed
+	addVkFormatDesc( X8_D24_UNORM_PACK32, Invalid, Depth24Unorm_Stencil8, Invalid, Invalid, 1, 1, 4, DepthStencil );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC1_RGB_UNORM_BLOCK, MTLPixelFormatBC1_RGBA, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC1_RGB_SRGB_BLOCK, MTLPixelFormatBC1_RGBA_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC1_RGBA_UNORM_BLOCK, MTLPixelFormatBC1_RGBA, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC1_RGBA_SRGB_BLOCK, MTLPixelFormatBC1_RGBA_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC1_RGB_UNORM_BLOCK, BC1_RGBA, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( BC1_RGB_SRGB_BLOCK, BC1_RGBA_sRGB, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( BC1_RGBA_UNORM_BLOCK, BC1_RGBA, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( BC1_RGBA_SRGB_BLOCK, BC1_RGBA_sRGB, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC2_UNORM_BLOCK, MTLPixelFormatBC2_RGBA, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC2_SRGB_BLOCK, MTLPixelFormatBC2_RGBA_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC2_UNORM_BLOCK, BC2_RGBA, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( BC2_SRGB_BLOCK, BC2_RGBA_sRGB, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC3_UNORM_BLOCK, MTLPixelFormatBC3_RGBA, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC3_SRGB_BLOCK, MTLPixelFormatBC3_RGBA_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC3_UNORM_BLOCK, BC3_RGBA, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( BC3_SRGB_BLOCK, BC3_RGBA_sRGB, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC4_UNORM_BLOCK, MTLPixelFormatBC4_RUnorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC4_SNORM_BLOCK, MTLPixelFormatBC4_RSnorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC4_UNORM_BLOCK, BC4_RUnorm, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( BC4_SNORM_BLOCK, BC4_RSnorm, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC5_UNORM_BLOCK, MTLPixelFormatBC5_RGUnorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC5_SNORM_BLOCK, MTLPixelFormatBC5_RGSnorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC5_UNORM_BLOCK, BC5_RGUnorm, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( BC5_SNORM_BLOCK, BC5_RGSnorm, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC6H_UFLOAT_BLOCK, MTLPixelFormatBC6H_RGBUfloat, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC6H_SFLOAT_BLOCK, MTLPixelFormatBC6H_RGBFloat, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC6H_UFLOAT_BLOCK, BC6H_RGBUfloat, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( BC6H_SFLOAT_BLOCK, BC6H_RGBFloat, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC7_UNORM_BLOCK, MTLPixelFormatBC7_RGBAUnorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_BC7_SRGB_BLOCK, MTLPixelFormatBC7_RGBAUnorm_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( BC7_UNORM_BLOCK, BC7_RGBAUnorm, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( BC7_SRGB_BLOCK, BC7_RGBAUnorm_sRGB, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, MTLPixelFormatETC2_RGB8, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, MTLPixelFormatETC2_RGB8_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, MTLPixelFormatETC2_RGB8A1, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, MTLPixelFormatETC2_RGB8A1_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( ETC2_R8G8B8_UNORM_BLOCK, ETC2_RGB8, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( ETC2_R8G8B8_SRGB_BLOCK, ETC2_RGB8_sRGB, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( ETC2_R8G8B8A1_UNORM_BLOCK, ETC2_RGB8A1, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( ETC2_R8G8B8A1_SRGB_BLOCK, ETC2_RGB8A1_sRGB, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, MTLPixelFormatEAC_RGBA8, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, MTLPixelFormatEAC_RGBA8_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( ETC2_R8G8B8A8_UNORM_BLOCK, EAC_RGBA8, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( ETC2_R8G8B8A8_SRGB_BLOCK, EAC_RGBA8_sRGB, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_EAC_R11_UNORM_BLOCK, MTLPixelFormatEAC_R11Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_EAC_R11_SNORM_BLOCK, MTLPixelFormatEAC_R11Snorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( EAC_R11_UNORM_BLOCK, EAC_R11Unorm, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( EAC_R11_SNORM_BLOCK, EAC_R11Snorm, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_EAC_R11G11_UNORM_BLOCK, MTLPixelFormatEAC_RG11Unorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_EAC_R11G11_SNORM_BLOCK, MTLPixelFormatEAC_RG11Snorm, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( EAC_R11G11_UNORM_BLOCK, EAC_RG11Unorm, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( EAC_R11G11_SNORM_BLOCK, EAC_RG11Snorm, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
 
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_4x4_UNORM_BLOCK, MTLPixelFormatASTC_4x4_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_4x4_SRGB_BLOCK, MTLPixelFormatASTC_4x4_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_5x4_UNORM_BLOCK, MTLPixelFormatASTC_5x4_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 5, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_5x4_SRGB_BLOCK, MTLPixelFormatASTC_5x4_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 5, 4, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_5x5_UNORM_BLOCK, MTLPixelFormatASTC_5x5_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 5, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_5x5_SRGB_BLOCK, MTLPixelFormatASTC_5x5_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 5, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_6x5_UNORM_BLOCK, MTLPixelFormatASTC_6x5_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 6, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_6x5_SRGB_BLOCK, MTLPixelFormatASTC_6x5_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 6, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_6x6_UNORM_BLOCK, MTLPixelFormatASTC_6x6_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 6, 6, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_6x6_SRGB_BLOCK, MTLPixelFormatASTC_6x6_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 6, 6, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_8x5_UNORM_BLOCK, MTLPixelFormatASTC_8x5_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_8x5_SRGB_BLOCK, MTLPixelFormatASTC_8x5_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_8x6_UNORM_BLOCK, MTLPixelFormatASTC_8x6_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 6, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_8x6_SRGB_BLOCK, MTLPixelFormatASTC_8x6_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 6, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_8x8_UNORM_BLOCK, MTLPixelFormatASTC_8x8_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 8, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_8x8_SRGB_BLOCK, MTLPixelFormatASTC_8x8_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 8, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x5_UNORM_BLOCK, MTLPixelFormatASTC_10x5_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x5_SRGB_BLOCK, MTLPixelFormatASTC_10x5_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 5, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x6_UNORM_BLOCK, MTLPixelFormatASTC_10x6_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 6, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x6_SRGB_BLOCK, MTLPixelFormatASTC_10x6_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 6, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x8_UNORM_BLOCK, MTLPixelFormatASTC_10x8_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 8, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x8_SRGB_BLOCK, MTLPixelFormatASTC_10x8_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 8, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x10_UNORM_BLOCK, MTLPixelFormatASTC_10x10_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 10, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_10x10_SRGB_BLOCK, MTLPixelFormatASTC_10x10_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 10, 10, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_12x10_UNORM_BLOCK, MTLPixelFormatASTC_12x10_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 12, 10, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_12x10_SRGB_BLOCK, MTLPixelFormatASTC_12x10_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 12, 10, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_12x12_UNORM_BLOCK, MTLPixelFormatASTC_12x12_LDR, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 12, 12, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_ASTC_12x12_SRGB_BLOCK, MTLPixelFormatASTC_12x12_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 12, 12, 16, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( ASTC_4x4_UNORM_BLOCK, ASTC_4x4_LDR, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( ASTC_4x4_SRGB_BLOCK, ASTC_4x4_sRGB, Invalid, Invalid, Invalid, 4, 4, 16, Compressed );
+	addVkFormatDesc( ASTC_5x4_UNORM_BLOCK, ASTC_5x4_LDR, Invalid, Invalid, Invalid, 5, 4, 16, Compressed );
+	addVkFormatDesc( ASTC_5x4_SRGB_BLOCK, ASTC_5x4_sRGB, Invalid, Invalid, Invalid, 5, 4, 16, Compressed );
+	addVkFormatDesc( ASTC_5x5_UNORM_BLOCK, ASTC_5x5_LDR, Invalid, Invalid, Invalid, 5, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_5x5_SRGB_BLOCK, ASTC_5x5_sRGB, Invalid, Invalid, Invalid, 5, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_6x5_UNORM_BLOCK, ASTC_6x5_LDR, Invalid, Invalid, Invalid, 6, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_6x5_SRGB_BLOCK, ASTC_6x5_sRGB, Invalid, Invalid, Invalid, 6, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_6x6_UNORM_BLOCK, ASTC_6x6_LDR, Invalid, Invalid, Invalid, 6, 6, 16, Compressed );
+	addVkFormatDesc( ASTC_6x6_SRGB_BLOCK, ASTC_6x6_sRGB, Invalid, Invalid, Invalid, 6, 6, 16, Compressed );
+	addVkFormatDesc( ASTC_8x5_UNORM_BLOCK, ASTC_8x5_LDR, Invalid, Invalid, Invalid, 8, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_8x5_SRGB_BLOCK, ASTC_8x5_sRGB, Invalid, Invalid, Invalid, 8, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_8x6_UNORM_BLOCK, ASTC_8x6_LDR, Invalid, Invalid, Invalid, 8, 6, 16, Compressed );
+	addVkFormatDesc( ASTC_8x6_SRGB_BLOCK, ASTC_8x6_sRGB, Invalid, Invalid, Invalid, 8, 6, 16, Compressed );
+	addVkFormatDesc( ASTC_8x8_UNORM_BLOCK, ASTC_8x8_LDR, Invalid, Invalid, Invalid, 8, 8, 16, Compressed );
+	addVkFormatDesc( ASTC_8x8_SRGB_BLOCK, ASTC_8x8_sRGB, Invalid, Invalid, Invalid, 8, 8, 16, Compressed );
+	addVkFormatDesc( ASTC_10x5_UNORM_BLOCK, ASTC_10x5_LDR, Invalid, Invalid, Invalid, 10, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_10x5_SRGB_BLOCK, ASTC_10x5_sRGB, Invalid, Invalid, Invalid, 10, 5, 16, Compressed );
+	addVkFormatDesc( ASTC_10x6_UNORM_BLOCK, ASTC_10x6_LDR, Invalid, Invalid, Invalid, 10, 6, 16, Compressed );
+	addVkFormatDesc( ASTC_10x6_SRGB_BLOCK, ASTC_10x6_sRGB, Invalid, Invalid, Invalid, 10, 6, 16, Compressed );
+	addVkFormatDesc( ASTC_10x8_UNORM_BLOCK, ASTC_10x8_LDR, Invalid, Invalid, Invalid, 10, 8, 16, Compressed );
+	addVkFormatDesc( ASTC_10x8_SRGB_BLOCK, ASTC_10x8_sRGB, Invalid, Invalid, Invalid, 10, 8, 16, Compressed );
+	addVkFormatDesc( ASTC_10x10_UNORM_BLOCK, ASTC_10x10_LDR, Invalid, Invalid, Invalid, 10, 10, 16, Compressed );
+	addVkFormatDesc( ASTC_10x10_SRGB_BLOCK, ASTC_10x10_sRGB, Invalid, Invalid, Invalid, 10, 10, 16, Compressed );
+	addVkFormatDesc( ASTC_12x10_UNORM_BLOCK, ASTC_12x10_LDR, Invalid, Invalid, Invalid, 12, 10, 16, Compressed );
+	addVkFormatDesc( ASTC_12x10_SRGB_BLOCK, ASTC_12x10_sRGB, Invalid, Invalid, Invalid, 12, 10, 16, Compressed );
+	addVkFormatDesc( ASTC_12x12_UNORM_BLOCK, ASTC_12x12_LDR, Invalid, Invalid, Invalid, 12, 12, 16, Compressed );
+	addVkFormatDesc( ASTC_12x12_SRGB_BLOCK, ASTC_12x12_sRGB, Invalid, Invalid, Invalid, 12, 12, 16, Compressed );
 
 	// Extension VK_IMG_format_pvrtc
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 4, 8, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 8, 4, 8, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 4, 4, 8, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS );
+	addVkFormatDesc( PVRTC1_2BPP_UNORM_BLOCK_IMG, PVRTC_RGBA_2BPP, Invalid, Invalid, Invalid, 8, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC1_4BPP_UNORM_BLOCK_IMG, PVRTC_RGBA_4BPP, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC2_2BPP_UNORM_BLOCK_IMG, Invalid, Invalid, Invalid, Invalid, 8, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC2_4BPP_UNORM_BLOCK_IMG, Invalid, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC1_2BPP_SRGB_BLOCK_IMG, PVRTC_RGBA_2BPP_sRGB, Invalid, Invalid, Invalid, 8, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC1_4BPP_SRGB_BLOCK_IMG, PVRTC_RGBA_4BPP_sRGB, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC2_2BPP_SRGB_BLOCK_IMG, Invalid, Invalid, Invalid, Invalid, 8, 4, 8, Compressed );
+	addVkFormatDesc( PVRTC2_4BPP_SRGB_BLOCK_IMG, Invalid, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
 
 	// Future extension VK_KHX_color_conversion and Vulkan 1.1.
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_UNDEFINED, MTLPixelFormatGBGR422, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 2, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
-	MVK_ADD_VKFMT_STRUCT( VK_FORMAT_UNDEFINED, MTLPixelFormatBGRG422, MTLPixelFormatInvalid, MTLVertexFormatInvalid, MTLVertexFormatInvalid, 2, 1, 4, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS );
+	addVkFormatDesc( UNDEFINED, GBGR422, Invalid, Invalid, Invalid, 2, 1, 4, ColorFloat );
+	addVkFormatDesc( UNDEFINED, BGRG422, Invalid, Invalid, Invalid, 2, 1, 4, ColorFloat );
 
 	// When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count
 }
 
-#define MVK_ADD_MTLPIXFMT_STRUCT(MTL_FMT, IOS_SINCE, MACOS_SINCE)  \
-	MVKAssert(fmtIdx < _mtlPixelFormatCount, "Attempting to describe %d MTLPixelFormats, but only have space for %d. Increase the value of _mtlPixelFormatCount", fmtIdx + 1, _mtlPixelFormatCount);		\
-	_mtlPixelFormatDescriptions[fmtIdx++] = { .mtlPixelFormat = MTL_FMT, VK_FORMAT_UNDEFINED, IOS_SINCE, MACOS_SINCE, #MTL_FMT }
+#define addMTLPixelFormatDesc(MTL_FMT, IOS_CAPS, MACOS_CAPS)  \
+	MVKAssert(fmtIdx < _mtlPixelFormatCount, "Attempting to describe %d MTLPixelFormats, but only have space for %d. Increase the value of _mtlPixelFormatCount", fmtIdx + 1, _mtlPixelFormatCount);  \
+	_mtlPixelFormatDescriptions[fmtIdx++] = { .mtlPixelFormat = MTLPixelFormat ##MTL_FMT, VK_FORMAT_UNDEFINED,  \
+											  mvkSelectPlatformValue<MVKMTLFmtCaps>(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS),  \
+											  "MTLPixelFormat" #MTL_FMT }
 
 void MVKPixelFormats::initMTLPixelFormatCapabilities() {
 
@@ -763,170 +726,170 @@
 	uint32_t fmtIdx = 0;
 
 	// When adding to this list, be sure to ensure _mtlPixelFormatCount is large enough for the format count
+
 	// MTLPixelFormatInvalid must come first.
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA );
+	addMTLPixelFormatDesc( Invalid, None, None );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatABGR4Unorm, 8.0, kMTLFmtNA );
+	// Ordinary 8-bit pixel formats
+	addMTLPixelFormatDesc( A8Unorm, RF, RF );
+	addMTLPixelFormatDesc( R8Unorm, All, All );
+	addMTLPixelFormatDesc( R8Unorm_sRGB, RFCMRB, None );
+	addMTLPixelFormatDesc( R8Snorm, RFWCMB, All );
+	addMTLPixelFormatDesc( R8Uint, RWCM, RWCM );
+	addMTLPixelFormatDesc( R8Sint, RWCM, RWCM );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatB5G6R5Unorm, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatA1BGR5Unorm, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBGR5A1Unorm, 8.0, kMTLFmtNA );
+	// Ordinary 16-bit pixel formats
+	addMTLPixelFormatDesc( R16Unorm, RFWCMB, All );
+	addMTLPixelFormatDesc( R16Snorm, RFWCMB, All );
+	addMTLPixelFormatDesc( R16Uint, RWCM, RWCM );
+	addMTLPixelFormatDesc( R16Sint, RWCM, RWCM );
+	addMTLPixelFormatDesc( R16Float, All, All );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR8Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR8Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR8Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR8Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR8Unorm_sRGB, 8.0, kMTLFmtNA );
+	addMTLPixelFormatDesc( RG8Unorm, All, All );
+	addMTLPixelFormatDesc( RG8Unorm_sRGB, RFCMRB, None );
+	addMTLPixelFormatDesc( RG8Snorm, RFWCMB, All );
+	addMTLPixelFormatDesc( RG8Uint, RWCM, RWCM );
+	addMTLPixelFormatDesc( RG8Sint, RWCM, RWCM );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG8Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG8Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG8Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG8Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG8Unorm_sRGB, 8.0, kMTLFmtNA );
+	// Packed 16-bit pixel formats
+	addMTLPixelFormatDesc( B5G6R5Unorm, RFCMRB, None );
+	addMTLPixelFormatDesc( A1BGR5Unorm, RFCMRB, None );
+	addMTLPixelFormatDesc( ABGR4Unorm, RFCMRB, None );
+	addMTLPixelFormatDesc( BGR5A1Unorm, RFCMRB, None );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Unorm_sRGB, 8.0, 10.11 );
+	// Ordinary 32-bit pixel formats
+	addMTLPixelFormatDesc( R32Uint, RC, RWCM );
+	addMTLPixelFormatDesc( R32Sint, RC, RWCM );
+	addMTLPixelFormatDesc( R32Float, RCMB, All );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBGRA8Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBGRA8Unorm_sRGB, 8.0, 10.11 );
+	addMTLPixelFormatDesc( RG16Unorm, RFWCMB, All );
+	addMTLPixelFormatDesc( RG16Snorm, RFWCMB, All );
+	addMTLPixelFormatDesc( RG16Uint, RWCM, RWCM );
+	addMTLPixelFormatDesc( RG16Sint, RWCM, RWCM );
+	addMTLPixelFormatDesc( RG16Float, All, All );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA8Unorm_sRGB, 8.0, 10.11 );
+	addMTLPixelFormatDesc( RGBA8Unorm, All, All );
+	addMTLPixelFormatDesc( RGBA8Unorm_sRGB, RFCMRB, RFCMRB );
+	addMTLPixelFormatDesc( RGBA8Snorm, RFWCMB, All );
+	addMTLPixelFormatDesc( RGBA8Uint, RWCM, RWCM );
+	addMTLPixelFormatDesc( RGBA8Sint, RWCM, RWCM );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBGR10A2Unorm, 11.0, 10.13 );
+	addMTLPixelFormatDesc( BGRA8Unorm, All, All );
+	addMTLPixelFormatDesc( BGRA8Unorm_sRGB, RFCMRB, RFCMRB );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGB10A2Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGB10A2Uint, 8.0, 10.11 );
+	// Packed 32-bit pixel formats
+	addMTLPixelFormatDesc( RGB10A2Unorm, RFCMRB, All );
+	addMTLPixelFormatDesc( RGB10A2Uint, RCM, RWCM );
+	addMTLPixelFormatDesc( RG11B10Float, RFCMRB, All );
+	addMTLPixelFormatDesc( RGB9E5Float, RFCMRB, RF );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR16Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR16Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR16Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR16Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR16Float, 8.0, 10.11 );
+	// Ordinary 64-bit pixel formats
+	addMTLPixelFormatDesc( RG32Uint, RC, RWCM );
+	addMTLPixelFormatDesc( RG32Sint, RC, RWCM );
+	addMTLPixelFormatDesc( RG32Float, RCB, All );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG16Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG16Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG16Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG16Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG16Float, 8.0, 10.11 );
+	addMTLPixelFormatDesc( RGBA16Unorm, RFWCMB, All );
+	addMTLPixelFormatDesc( RGBA16Snorm, RFWCMB, All );
+	addMTLPixelFormatDesc( RGBA16Uint, RWCM, RWCM );
+	addMTLPixelFormatDesc( RGBA16Sint, RWCM, RWCM );
+	addMTLPixelFormatDesc( RGBA16Float, All, All );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA16Unorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA16Snorm, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA16Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA16Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA16Float, 8.0, 10.11 );
+	// Ordinary 128-bit pixel formats
+	addMTLPixelFormatDesc( RGBA32Uint, RC, RWCM );
+	addMTLPixelFormatDesc( RGBA32Sint, RC, RWCM );
+	addMTLPixelFormatDesc( RGBA32Float, RC, All );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR32Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR32Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatR32Float, 8.0, 10.11 );
+	// Compressed pixel formats
+	addMTLPixelFormatDesc( PVRTC_RGBA_2BPP, RF, None );
+	addMTLPixelFormatDesc( PVRTC_RGBA_4BPP, RF, None );
+	addMTLPixelFormatDesc( PVRTC_RGBA_2BPP_sRGB, RF, None );
+	addMTLPixelFormatDesc( PVRTC_RGBA_4BPP_sRGB, RF, None );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG32Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG32Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG32Float, 8.0, 10.11 );
+	addMTLPixelFormatDesc( ETC2_RGB8, RF, None );
+	addMTLPixelFormatDesc( ETC2_RGB8_sRGB, RF, None );
+	addMTLPixelFormatDesc( ETC2_RGB8A1, RF, None );
+	addMTLPixelFormatDesc( ETC2_RGB8A1_sRGB, RF, None );
+	addMTLPixelFormatDesc( EAC_RGBA8, RF, None );
+	addMTLPixelFormatDesc( EAC_RGBA8_sRGB, RF, None );
+	addMTLPixelFormatDesc( EAC_R11Unorm, RF, None );
+	addMTLPixelFormatDesc( EAC_R11Snorm, RF, None );
+	addMTLPixelFormatDesc( EAC_RG11Unorm, RF, None );
+	addMTLPixelFormatDesc( EAC_RG11Snorm, RF, None );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA32Uint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA32Sint, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGBA32Float, 8.0, 10.11 );
+	addMTLPixelFormatDesc( ASTC_4x4_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_4x4_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_5x4_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_5x4_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_5x5_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_5x5_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_6x5_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_6x5_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_6x6_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_6x6_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_8x5_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_8x5_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_8x6_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_8x6_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_8x8_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_8x8_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_10x5_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_10x5_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_10x6_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_10x6_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_10x8_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_10x8_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_10x10_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_10x10_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_12x10_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_12x10_sRGB, None, None );
+	addMTLPixelFormatDesc( ASTC_12x12_LDR, None, None );
+	addMTLPixelFormatDesc( ASTC_12x12_sRGB, None, None );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRG11B10Float, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatRGB9E5Float, 8.0, 10.11 );
+	addMTLPixelFormatDesc( BC1_RGBA, None, RF );
+	addMTLPixelFormatDesc( BC1_RGBA_sRGB, None, RF );
+	addMTLPixelFormatDesc( BC1_RGBA, None, RF );
+	addMTLPixelFormatDesc( BC1_RGBA_sRGB, None, RF );
+	addMTLPixelFormatDesc( BC2_RGBA, None, RF );
+	addMTLPixelFormatDesc( BC2_RGBA_sRGB, None, RF );
+	addMTLPixelFormatDesc( BC3_RGBA, None, RF );
+	addMTLPixelFormatDesc( BC3_RGBA_sRGB, None, RF );
+	addMTLPixelFormatDesc( BC4_RUnorm, None, RF );
+	addMTLPixelFormatDesc( BC4_RSnorm, None, RF );
+	addMTLPixelFormatDesc( BC5_RGUnorm, None, RF );
+	addMTLPixelFormatDesc( BC5_RGSnorm, None, RF );
+	addMTLPixelFormatDesc( BC6H_RGBUfloat, None, RF );
+	addMTLPixelFormatDesc( BC6H_RGBFloat, None, RF );
+	addMTLPixelFormatDesc( BC7_RGBAUnorm, None, RF );
+	addMTLPixelFormatDesc( BC7_RGBAUnorm_sRGB, None, RF );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatDepth32Float, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatDepth32Float_Stencil8, 9.0, 10.11 );
+	// YUV pixel formats
+	addMTLPixelFormatDesc( GBGR422, RF, RF );
+	addMTLPixelFormatDesc( BGRG422, RF, RF );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatStencil8, 8.0, 10.11 );
+	// Depth and stencil pixel formats
+	addMTLPixelFormatDesc( Depth16Unorm, None, None );
+	addMTLPixelFormatDesc( Depth32Float, DRM, DRFMR );
+	addMTLPixelFormatDesc( Stencil8, DRM, DRM );
+	addMTLPixelFormatDesc( Depth24Unorm_Stencil8, None, None );
+	addMTLPixelFormatDesc( Depth32Float_Stencil8, DRM, DRFMR );
+	addMTLPixelFormatDesc( X24_Stencil8, None, DRM );
+	addMTLPixelFormatDesc( X32_Stencil8, DRM, DRM );
 
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatDepth16Unorm, kMTLFmtNA, 10.12 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatDepth24Unorm_Stencil8, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC1_RGBA, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC1_RGBA_sRGB, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC1_RGBA, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC1_RGBA_sRGB, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC2_RGBA, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC2_RGBA_sRGB, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC3_RGBA, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC3_RGBA_sRGB, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC4_RUnorm, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC4_RSnorm, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC5_RGUnorm, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC5_RGSnorm, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC6H_RGBUfloat, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC6H_RGBFloat, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC7_RGBAUnorm, kMTLFmtNA, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBC7_RGBAUnorm_sRGB, kMTLFmtNA, 10.11 );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatETC2_RGB8, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatETC2_RGB8_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatETC2_RGB8A1, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatETC2_RGB8A1_sRGB, 8.0, kMTLFmtNA );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatEAC_RGBA8, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatEAC_RGBA8_sRGB, 8.0, kMTLFmtNA );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatEAC_R11Unorm, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatEAC_R11Snorm, 8.0, kMTLFmtNA );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatEAC_RG11Unorm, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatEAC_RG11Snorm, 8.0, kMTLFmtNA );
-
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_4x4_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_4x4_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_5x4_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_5x4_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_5x5_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_5x5_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_6x5_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_6x5_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_6x6_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_6x6_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_8x5_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_8x5_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_8x6_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_8x6_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_8x8_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_8x8_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x5_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x5_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x6_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x6_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x8_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x8_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x10_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_10x10_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_12x10_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_12x10_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_12x12_LDR, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatASTC_12x12_sRGB, 8.0, kMTLFmtNA );
-
-	// Extension VK_IMG_format_pvrtc
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatPVRTC_RGBA_2BPP, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatPVRTC_RGBA_4BPP, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, 8.0, kMTLFmtNA );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, 8.0, kMTLFmtNA );
-
-	// Future extension VK_KHX_color_conversion and Vulkan 1.1.
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatGBGR422, 8.0, 10.11 );
-	MVK_ADD_MTLPIXFMT_STRUCT( MTLPixelFormatBGRG422, 8.0, 10.11 );
+	// Extended range and wide color pixel formats
+	addMTLPixelFormatDesc( BGRA10_XR, None, None );
+	addMTLPixelFormatDesc( BGRA10_XR_sRGB, None, None );
+	addMTLPixelFormatDesc( BGR10_XR, None, None );
+	addMTLPixelFormatDesc( BGR10_XR_sRGB, None, None );
+	addMTLPixelFormatDesc( BGR10A2Unorm, None, None );
 
 	// When adding to this list, be sure to ensure _mtlPixelFormatCount is large enough for the format count
 }
 
-#define MVK_ADD_MTLVTXFMT_STRUCT(MTL_VTX_FMT, VTX_IOS_SINCE, VTX_MACOS_SINCE)  \
-	MVKAssert(fmtIdx < _mtlVertexFormatCount, "Attempting to describe %d MTLVertexFormats, but only have space for %d. Increase the value of _mtlVertexFormatCount", fmtIdx + 1, _mtlVertexFormatCount);		\
-	_mtlVertexFormatDescriptions[fmtIdx++] = { .mtlVertexFormat = MTL_VTX_FMT, VK_FORMAT_UNDEFINED, VTX_IOS_SINCE, VTX_MACOS_SINCE, #MTL_VTX_FMT }
+#define addMTLVertexFormatDesc(MTL_VTX_FMT, IOS_CAPS, MACOS_CAPS)  \
+	MVKAssert(fmtIdx < _mtlVertexFormatCount, "Attempting to describe %d MTLVertexFormats, but only have space for %d. Increase the value of _mtlVertexFormatCount", fmtIdx + 1, _mtlVertexFormatCount);  \
+	_mtlVertexFormatDescriptions[fmtIdx++] = { .mtlVertexFormat = MTLVertexFormat ##MTL_VTX_FMT, VK_FORMAT_UNDEFINED,  \
+                                               mvkSelectPlatformValue<MVKMTLFmtCaps>(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS),  \
+                                               "MTLVertexFormat" #MTL_VTX_FMT }
 
 void MVKPixelFormats::initMTLVertexFormatCapabilities() {
 
@@ -936,81 +899,80 @@
 
 	// When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count
 	// MTLVertexFormatInvalid must come first.
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA );
+	addMTLVertexFormatDesc( Invalid, None, None );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUCharNormalized, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatCharNormalized, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar, 11.0, 10.13 );
+	addMTLVertexFormatDesc( UChar2Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Char2Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( UChar2, Vertex, Vertex );
+	addMTLVertexFormatDesc( Char2, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar2Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar2Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar2, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar2, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UChar3Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Char3Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( UChar3, Vertex, Vertex );
+	addMTLVertexFormatDesc( Char3, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar3Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar3Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar3, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar3, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UChar4Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Char4Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( UChar4, Vertex, Vertex );
+	addMTLVertexFormatDesc( Char4, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar4Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar4Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar4, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatChar4, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UInt1010102Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Int1010102Normalized, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUChar4Normalized_BGRA, 11.0, 10.13 );
+	addMTLVertexFormatDesc( UShort2Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Short2Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( UShort2, Vertex, Vertex );
+	addMTLVertexFormatDesc( Short2, Vertex, Vertex );
+	addMTLVertexFormatDesc( Half2, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUInt1010102Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatInt1010102Normalized, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UShort3Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Short3Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( UShort3, Vertex, Vertex );
+	addMTLVertexFormatDesc( Short3, Vertex, Vertex );
+	addMTLVertexFormatDesc( Half3, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShortNormalized, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShortNormalized, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort, 11.0, 10.13 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatHalf, 11.0, 10.13 );
+	addMTLVertexFormatDesc( UShort4Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( Short4Normalized, Vertex, Vertex );
+	addMTLVertexFormatDesc( UShort4, Vertex, Vertex );
+	addMTLVertexFormatDesc( Short4, Vertex, Vertex );
+	addMTLVertexFormatDesc( Half4, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort2Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort2Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort2, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort2, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatHalf2, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UInt, Vertex, Vertex );
+	addMTLVertexFormatDesc( Int, Vertex, Vertex );
+	addMTLVertexFormatDesc( Float, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort3Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort3Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort3, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort3, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatHalf3, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UInt2, Vertex, Vertex );
+	addMTLVertexFormatDesc( Int2, Vertex, Vertex );
+	addMTLVertexFormatDesc( Float2, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort4Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort4Normalized, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUShort4, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatShort4, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatHalf4, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UInt3, Vertex, Vertex );
+	addMTLVertexFormatDesc( Int3, Vertex, Vertex );
+	addMTLVertexFormatDesc( Float3, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUInt, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatInt, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatFloat, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UInt4, Vertex, Vertex );
+	addMTLVertexFormatDesc( Int4, Vertex, Vertex );
+	addMTLVertexFormatDesc( Float4, Vertex, Vertex );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUInt2, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatInt2, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatFloat2, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UCharNormalized, None, None );
+	addMTLVertexFormatDesc( CharNormalized, None, None );
+	addMTLVertexFormatDesc( UChar, None, None );
+	addMTLVertexFormatDesc( Char, None, None );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUInt3, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatInt3, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatFloat3, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UShortNormalized, None, None );
+	addMTLVertexFormatDesc( ShortNormalized, None, None );
+	addMTLVertexFormatDesc( UShort, None, None );
+	addMTLVertexFormatDesc( Short, None, None );
+	addMTLVertexFormatDesc( Half, None, None );
 
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatUInt4, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatInt4, 8.0, 10.11 );
-	MVK_ADD_MTLVTXFMT_STRUCT( MTLVertexFormatFloat4, 8.0, 10.11 );
+	addMTLVertexFormatDesc( UChar4Normalized_BGRA, None, None );
 
 	// When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count
 }
 
-// Populates the lookup maps that map Vulkan and Metal pixel formats to one-another.
-void MVKPixelFormats::buildFormatMaps() {
+// Populates the Metal lookup maps
+void MVKPixelFormats::buildMTLFormatMaps() {
 
-	// Set all VkFormats, MTLPixelFormats, and MTLVertexFormats to undefined/invalid
-	mvkClear(_vkFormatDescIndicesByVkFormatsCore, _vkFormatCoreCount);
+	// Set all MTLPixelFormats and MTLVertexFormats to undefined/invalid
 	mvkClear(_mtlFormatDescIndicesByMTLPixelFormats, _mtlPixelFormatCount);
 	mvkClear(_mtlFormatDescIndicesByMTLVertexFormats, _mtlVertexFormatCount);
 
@@ -1025,6 +987,158 @@
 		MTLVertexFormat fmt = _mtlVertexFormatDescriptions[fmtIdx].mtlVertexFormat;
 		if (fmt) { _mtlFormatDescIndicesByMTLVertexFormats[fmt] = fmtIdx; }
 	}
+}
+
+// If the device supports the feature set, add additional capabilities to a MTLPixelFormat
+void MVKPixelFormats::addMTLPixelFormatCapabilities(id<MTLDevice> mtlDevice,
+													MTLFeatureSet mtlFeatSet,
+													MTLPixelFormat mtlPixFmt,
+													MVKMTLFmtCaps mtlFmtCaps) {
+	if ( [mtlDevice supportsFeatureSet: mtlFeatSet] ) {
+		mvkEnableFlags(getMTLPixelFormatDesc(mtlPixFmt).mtlFmtCaps, mtlFmtCaps);
+	}
+}
+
+// If the device supports the feature set, add additional capabilities to a MTLVertexFormat
+void MVKPixelFormats::addMTLVertexFormatCapabilities(id<MTLDevice> mtlDevice,
+													 MTLFeatureSet mtlFeatSet,
+													 MTLVertexFormat mtlVtxFmt,
+													 MVKMTLFmtCaps mtlFmtCaps) {
+	if ( [mtlDevice supportsFeatureSet: mtlFeatSet] ) {
+		mvkEnableFlags(getMTLVertexFormatDesc(mtlVtxFmt).mtlFmtCaps, mtlFmtCaps);
+	}
+}
+
+#define addMTLPixelFormatCapabilities(FEAT_SET, MTL_FMT, CAPS)  \
+	addMTLPixelFormatCapabilities(mtlDevice, MTLFeatureSet_ ##FEAT_SET, MTLPixelFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS)
+
+#define addMTLVertexFormatCapabilities(FEAT_SET, MTL_FMT, CAPS)  \
+	addMTLVertexFormatCapabilities(mtlDevice, MTLFeatureSet_ ##FEAT_SET, MTLVertexFormat ##MTL_FMT, kMVKMTLFmtCaps ##CAPS)
+
+// Modifies the format capability tables based on the capabilities of the specific MTLDevice
+#if MVK_MACOS
+void MVKPixelFormats::modifyMTLFormatCapabilities(id<MTLDevice> mtlDevice) {
+	if ( !mtlDevice ) { return; }
+
+	if (mtlDevice.isDepth24Stencil8PixelFormatSupported) {
+		addMTLPixelFormatCapabilities( macOS_GPUFamily1_v1, Depth24Unorm_Stencil8, DRFMR );
+	}
+
+	addMTLPixelFormatCapabilities( macOS_GPUFamily1_v2, Depth16Unorm, DRFMR );
+
+	addMTLPixelFormatCapabilities( macOS_GPUFamily1_v3, BGR10A2Unorm, RFCMRB );
+
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, UCharNormalized, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, CharNormalized, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, UChar, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, Char, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, UShortNormalized, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, ShortNormalized, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, UShort, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, Short, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, Half, Vertex );
+	addMTLVertexFormatCapabilities( macOS_GPUFamily1_v3, UChar4Normalized_BGRA, Vertex );
+}
+#endif
+#if MVK_IOS
+void MVKPixelFormats::modifyMTLFormatCapabilities(id<MTLDevice> mtlDevice) {
+	if ( !mtlDevice ) { return; }
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v3, R8Unorm_sRGB, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, R8Unorm_sRGB, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, R8Snorm, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v3, RG8Unorm_sRGB, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, RG8Unorm_sRGB, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, RG8Snorm, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, R32Uint, RWC );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, R32Sint, RWC );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, R32Float, RWCMB );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v3, RGBA8Unorm_sRGB, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, RGBA8Unorm_sRGB, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, RGBA8Snorm, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v3, BGRA8Unorm_sRGB, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, BGRA8Unorm_sRGB, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, RGB10A2Unorm, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, RGB10A2Uint, RWCM );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, RG11B10Float, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, RGB9E5Float, All );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RG32Uint, RWC );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RG32Sint, RWC );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RG32Float, RWCB );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RGBA32Uint, RWC );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RGBA32Sint, RWC );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RGBA32Float, RWC );
+
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_4x4_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_4x4_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x4_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x4_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x5_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x5_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x5_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x5_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x6_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x6_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x5_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x5_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x6_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x6_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x8_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x8_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x5_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x5_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x6_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x6_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x8_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x8_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x10_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x10_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x10_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x10_sRGB, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x12_LDR, RF );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x12_sRGB, RF );
+
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, Depth32Float, DRMR );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, Depth32Float_Stencil8, DRMR );
+
+	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGRA10_XR, All );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGRA10_XR_sRGB, All );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGR10_XR, All );
+	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGR10_XR_sRGB, All );
+
+	addMTLPixelFormatCapabilities(iOS_GPUFamily1_v4, BGR10A2Unorm, All );
+
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, UCharNormalized, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, CharNormalized, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, UChar, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, Char, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, UShortNormalized, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, ShortNormalized, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, UShort, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, Short, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, Half, Vertex );
+	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, UChar4Normalized_BGRA, Vertex );
+}
+#endif
+#undef addMTLPixelFormatCapabilities
+#undef addMTLVertexFormatCapabilities
+
+// Populates the VkFormat lookup maps and connects Vulkan and Metal pixel formats to one-another.
+void MVKPixelFormats::buildVkFormatMaps() {
+
+	// Set the VkFormats to undefined/invalid
+	mvkClear(_vkFormatDescIndicesByVkFormatsCore, _vkFormatCoreCount);
 
 	// Iterate through the VkFormat descriptions, populate the lookup maps and back pointers,
 	// and validate the Metal formats for the platform and OS.
@@ -1062,93 +1176,184 @@
 				auto& mtlDesc = getMTLVertexFormatDesc(vkDesc.mtlVertexFormatSubstitute);
 				if ( !mtlDesc.isSupported() ) { vkDesc.mtlVertexFormatSubstitute = MTLVertexFormatInvalid; }
 			}
+
+			// Vulkan format features
+			MVKFormatType fmtType = vkDesc.formatType;
+			MVKMTLFmtCaps mtlPixFmtCaps = getMTLPixelFormatDesc(vkFmt).mtlFmtCaps;
+			MVKMTLFmtCaps mtlVtxFmtCaps = getMTLVertexFormatDesc(vkFmt).mtlFmtCaps;
+			vkDesc.properties = { getLinearTilingFeatures(mtlPixFmtCaps, fmtType),
+								  getOptimalTilingFeatures(mtlPixFmtCaps),
+								  getBufferFeatures(mtlPixFmtCaps, mtlVtxFmtCaps, fmtType) };
 		}
 	}
 }
 
-// Modifies the format capability tables based on the capabilities of the specific MTLDevice
-void MVKPixelFormats::modifyFormatCapabilitiesForMTLDevice(id<MTLDevice> mtlDevice) {
-	if ( !mtlDevice ) { return; }
+// Enumeration of Vulkan format features aligned to the MVKMTLFmtCaps enumeration.
+typedef enum : VkFormatFeatureFlags {
+	kMVKVkFormatFeatureFlagsTexNone     = 0,
+	kMVKVkFormatFeatureFlagsTexRead     = (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
+										   VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
+										   VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
+										   VK_FORMAT_FEATURE_BLIT_SRC_BIT),
+	kMVKVkFormatFeatureFlagsTexFilter   = (VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT),
+	kMVKVkFormatFeatureFlagsTexWrite    = (VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
+										   VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT),
+	kMVKVkFormatFeatureFlagsTexColorAtt = (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
+										   VK_FORMAT_FEATURE_BLIT_DST_BIT),
+	kMVKVkFormatFeatureFlagsTexDSAtt    = (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT),
+	kMVKVkFormatFeatureFlagsTexBlend    = (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT),
+	kMVKVkFormatFeatureFlagsBufRead     = (VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT),
+	kMVKVkFormatFeatureFlagsBufWrite    = (VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT |
+										   VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT),
+	kMVKVkFormatFeatureFlagsBufVertex   = (VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT),
+} MVKVkFormatFeatureFlags;
 
-#if MVK_MACOS
-	if ( !mtlDevice.isDepth24Stencil8PixelFormatSupported ) {
-		disableMTLPixelFormat(MTLPixelFormatDepth24Unorm_Stencil8);
+#define enableTexFormatFeatures(CAP)  \
+	if (mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCaps ##CAP)) {  \
+		vkFeatures |= kMVKVkFormatFeatureFlagsTex ##CAP;  \
 	}
-#endif
+VkFormatFeatureFlags MVKPixelFormats::getOptimalTilingFeatures(MVKMTLFmtCaps mtlFmtCaps) {
+	VkFormatFeatureFlags vkFeatures = kMVKVkFormatFeatureFlagsTexNone;
+	enableTexFormatFeatures(Read);
+	enableTexFormatFeatures(Filter);
+	enableTexFormatFeatures(Write);
+	enableTexFormatFeatures(ColorAtt);
+	enableTexFormatFeatures(DSAtt);
+	enableTexFormatFeatures(Blend);
+	return vkFeatures;
 }
 
-void MVKPixelFormats::disableMTLPixelFormat(MTLPixelFormat mtlFormat) {
-	getVkFormatDesc(mtlFormat).mtlPixelFormat = MTLPixelFormatInvalid;
+VkFormatFeatureFlags MVKPixelFormats::getLinearTilingFeatures(MVKMTLFmtCaps mtlFmtCaps,
+															  MVKFormatType mvkFmtType) {
+
+	// Depth-stencil or compressed formats cannot be used for linear textures.
+	if (mvkFmtType == kMVKFormatDepthStencil || mvkFmtType == kMVKFormatCompressed) {
+		return kMVKVkFormatFeatureFlagsTexNone;
+	}
+
+	// Start with the optimal features.
+	VkFormatFeatureFlags vkFeatures = getOptimalTilingFeatures(mtlFmtCaps);
+
+#if MVK_MACOS
+	// On macOS, linear textures cannot be used as attachments, so disable those features.
+	mvkDisableFlags(vkFeatures, (kMVKVkFormatFeatureFlagsTexColorAtt |
+								 kMVKVkFormatFeatureFlagsTexDSAtt |
+								 kMVKVkFormatFeatureFlagsTexBlend));
+#endif
+
+	return vkFeatures;
+}
+
+VkFormatFeatureFlags MVKPixelFormats::getBufferFeatures(MVKMTLFmtCaps mtlPixFmtCaps,
+														MVKMTLFmtCaps mtlVtxFmtCaps,
+														MVKFormatType mvkFmtType) {
+
+	// Depth-stencil or compressed formats cannot be used for texel buffers.
+	if (mvkFmtType == kMVKFormatDepthStencil || mvkFmtType == kMVKFormatCompressed) {
+		return kMVKVkFormatFeatureFlagsTexNone;
+	}
+
+	VkFormatFeatureFlags vkFeatures = kMVKVkFormatFeatureFlagsTexNone;
+	if (mvkAreAllFlagsEnabled(mtlPixFmtCaps, kMVKMTLFmtCapsRead)) {
+		vkFeatures |= kMVKVkFormatFeatureFlagsBufRead;
+	}
+	if (mvkAreAllFlagsEnabled(mtlPixFmtCaps, kMVKMTLFmtCapsWrite)) {
+		vkFeatures |= kMVKVkFormatFeatureFlagsBufWrite;
+	}
+	if (mvkAreAllFlagsEnabled(mtlVtxFmtCaps, kMVKMTLFmtCapsVertex)) {
+		vkFeatures |= kMVKVkFormatFeatureFlagsBufVertex;
+	}
+	return vkFeatures;
 }
 
 
 #pragma mark -
 #pragma mark Unit Testing
 
-// Validate the functionality of this class against the previous format data within MoltenVK.
-// This is a temporary function to confirm that converting to using this class matches existing behaviour at first.
-void MVKPixelFormats::test() {
-	if (_apiObject) { return; }		// Only test default platform formats
-
-#define MVK_TEST_FMT(V1, V2)	testFmt(V1, V2, fd.name, #V1)
-
-	MVKLogInfo("Starting testing formats");
-	for (uint32_t fmtIdx = 0; fmtIdx < _vkFormatCount; fmtIdx++) {
-		auto& fd = _vkFormatDescriptions[fmtIdx];
-		VkFormat vkFmt = fd.vkFormat;
-		MTLPixelFormat mtlFmt = fd.mtlPixelFormat;
-
-		if (fd.vkFormat) {
-			if (fd.isSupportedOrSubstitutable()) {
-				MVKLogInfo("Testing %s", fd.name);
-
-				MVK_TEST_FMT(vkFormatIsSupported(vkFmt), mvkVkFormatIsSupported(vkFmt));
-				MVK_TEST_FMT(mtlPixelFormatIsSupported(mtlFmt), mvkMTLPixelFormatIsSupported(mtlFmt));
-				MVK_TEST_FMT(mtlPixelFormatIsDepthFormat(mtlFmt), mvkMTLPixelFormatIsDepthFormat(mtlFmt));
-				MVK_TEST_FMT(mtlPixelFormatIsStencilFormat(mtlFmt), mvkMTLPixelFormatIsStencilFormat(mtlFmt));
-				MVK_TEST_FMT(mtlPixelFormatIsPVRTCFormat(mtlFmt), mvkMTLPixelFormatIsPVRTCFormat(mtlFmt));
-				MVK_TEST_FMT(getFormatTypeFromVkFormat(vkFmt), mvkFormatTypeFromVkFormat(vkFmt));
-				MVK_TEST_FMT(getFormatTypeFromMTLPixelFormat(mtlFmt), mvkFormatTypeFromMTLPixelFormat(mtlFmt));
-				MVK_TEST_FMT(getMTLPixelFormatFromVkFormat(vkFmt), mvkMTLPixelFormatFromVkFormat(vkFmt));
-				MVK_TEST_FMT(getVkFormatFromMTLPixelFormat(mtlFmt), mvkVkFormatFromMTLPixelFormat(mtlFmt));
-				MVK_TEST_FMT(getVkFormatBytesPerBlock(vkFmt), mvkVkFormatBytesPerBlock(vkFmt));
-				MVK_TEST_FMT(getMTLPixelFormatBytesPerBlock(mtlFmt), mvkMTLPixelFormatBytesPerBlock(mtlFmt));
-				MVK_TEST_FMT(getVkFormatBlockTexelSize(vkFmt), mvkVkFormatBlockTexelSize(vkFmt));
-				MVK_TEST_FMT(getMTLPixelFormatBlockTexelSize(mtlFmt), mvkMTLPixelFormatBlockTexelSize(mtlFmt));
-				MVK_TEST_FMT(getVkFormatBytesPerTexel(vkFmt), mvkVkFormatBytesPerTexel(vkFmt));
-				MVK_TEST_FMT(getMTLPixelFormatBytesPerTexel(mtlFmt), mvkMTLPixelFormatBytesPerTexel(mtlFmt));
-				MVK_TEST_FMT(getVkFormatBytesPerRow(vkFmt, 4), mvkVkFormatBytesPerRow(vkFmt, 4));
-				MVK_TEST_FMT(getMTLPixelFormatBytesPerRow(mtlFmt, 4), mvkMTLPixelFormatBytesPerRow(mtlFmt, 4));
-				MVK_TEST_FMT(getVkFormatBytesPerLayer(vkFmt, 256, 4), mvkVkFormatBytesPerLayer(vkFmt, 256, 4));
-				MVK_TEST_FMT(getMTLPixelFormatBytesPerLayer(mtlFmt, 256, 4), mvkMTLPixelFormatBytesPerLayer(mtlFmt, 256, 4));
-				MVK_TEST_FMT(getVkFormatProperties(vkFmt), mvkVkFormatProperties(vkFmt));
-				MVK_TEST_FMT(strcmp(getVkFormatName(vkFmt), mvkVkFormatName(vkFmt)), 0);
-				MVK_TEST_FMT(strcmp(getMTLPixelFormatName(mtlFmt), mvkMTLPixelFormatName(mtlFmt)), 0);
-				MVK_TEST_FMT(getMTLClearColorFromVkClearValue(VkClearValue(), vkFmt),
-							 mvkMTLClearColorFromVkClearValue(VkClearValue(), vkFmt));
-
-				MVK_TEST_FMT(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageUnknown, mtlFmt),
-							 mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageUnknown, mtlFmt));
-				MVK_TEST_FMT(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderRead, mtlFmt),
-							 mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderRead, mtlFmt));
-				MVK_TEST_FMT(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderWrite, mtlFmt),
-							 mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderWrite, mtlFmt));
-				MVK_TEST_FMT(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageRenderTarget, mtlFmt),
-							 mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageRenderTarget, mtlFmt));
-				MVK_TEST_FMT(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsagePixelFormatView, mtlFmt),
-							 mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsagePixelFormatView, mtlFmt));
-
-				MVK_TEST_FMT(getMTLVertexFormatFromVkFormat(vkFmt), mvkMTLVertexFormatFromVkFormat(vkFmt));
-
-			} else {
-				MVKLogInfo("%s not supported or substitutable on this device.", fd.name);
-			}
-		}
-	}
-	MVKLogInfo("Finished testing formats.\n");
-}
-
 template<typename T>
 void MVKPixelFormats::testFmt(const T v1, const T v2, const char* fmtName, const char* funcName) {
 	MVKAssert(mvkAreEqual(&v1,&v2), "Results not equal for format %s on test %s.", fmtName, funcName);
 }
+
+void MVKPixelFormats::testProps(const VkFormatProperties p1, const VkFormatProperties p2, const char* fmtName) {
+	MVKLogErrorIf(!mvkAreEqual(&p1, &p2),
+				  "Properties not equal for format %s. "
+				  "\n\tgetVkFormatProperties() linear %d, optimal %d, buffer %d. "
+				  "\n\tmvkVkFormatProperties(): linear %d, optimal %d, buffer %d"
+				  "\n\tdifference: linear %d, optimal %d, buffer %d", fmtName,
+				  p1.linearTilingFeatures, p1.optimalTilingFeatures, p1.bufferFeatures,
+				  p2.linearTilingFeatures, p2.optimalTilingFeatures, p2.bufferFeatures,
+				  std::abs((int)p2.linearTilingFeatures - (int)p1.linearTilingFeatures),
+				  std::abs((int)p2.optimalTilingFeatures - (int)p1.optimalTilingFeatures),
+				  std::abs((int)p2.bufferFeatures - (int)p1.bufferFeatures));
+}
+
+// Validate the functionality of this class against the previous format data within MoltenVK.
+// This is a temporary function to confirm that converting to using this class matches existing behaviour at first.
+void MVKPixelFormats::test(id<MTLDevice> mtlDevice) {
+	@autoreleasepool {
+		// Don't test a static instance, and only test the default MTLDevice if more than one GPU.
+		if ( !_apiObject || mtlDevice != [MTLCreateSystemDefaultDevice() autorelease] ) { return; }
+
+		MVKLogInfo("Starting testing formats");
+		for (uint32_t fmtIdx = 0; fmtIdx < _vkFormatCount; fmtIdx++) {
+			auto& fd = _vkFormatDescriptions[fmtIdx];
+			VkFormat vkFmt = fd.vkFormat;
+			MTLPixelFormat mtlFmt = fd.mtlPixelFormat;
+
+			if (fd.vkFormat) {
+				if (fd.isSupportedOrSubstitutable()) {
+					MVKLogInfo("Testing %s", fd.name);
+
+#					define testFmt(V1, V2)	  testFmt(V1, V2, fd.name, #V1)
+#					define testProps(V1, V2)  testProps(V1, V2, fd.name)
+
+					testFmt(vkFormatIsSupported(vkFmt), mvkVkFormatIsSupported(vkFmt));
+					testFmt(mtlPixelFormatIsSupported(mtlFmt), mvkMTLPixelFormatIsSupported(mtlFmt));
+					testFmt(mtlPixelFormatIsDepthFormat(mtlFmt), mvkMTLPixelFormatIsDepthFormat(mtlFmt));
+					testFmt(mtlPixelFormatIsStencilFormat(mtlFmt), mvkMTLPixelFormatIsStencilFormat(mtlFmt));
+					testFmt(mtlPixelFormatIsPVRTCFormat(mtlFmt), mvkMTLPixelFormatIsPVRTCFormat(mtlFmt));
+					testFmt(getFormatTypeFromVkFormat(vkFmt), mvkFormatTypeFromVkFormat(vkFmt));
+					testFmt(getFormatTypeFromMTLPixelFormat(mtlFmt), mvkFormatTypeFromMTLPixelFormat(mtlFmt));
+					testFmt(getMTLPixelFormatFromVkFormat(vkFmt), mvkMTLPixelFormatFromVkFormat(vkFmt));
+					testFmt(getVkFormatFromMTLPixelFormat(mtlFmt), mvkVkFormatFromMTLPixelFormat(mtlFmt));
+					testFmt(getVkFormatBytesPerBlock(vkFmt), mvkVkFormatBytesPerBlock(vkFmt));
+					testFmt(getMTLPixelFormatBytesPerBlock(mtlFmt), mvkMTLPixelFormatBytesPerBlock(mtlFmt));
+					testFmt(getVkFormatBlockTexelSize(vkFmt), mvkVkFormatBlockTexelSize(vkFmt));
+					testFmt(getMTLPixelFormatBlockTexelSize(mtlFmt), mvkMTLPixelFormatBlockTexelSize(mtlFmt));
+					testFmt(getVkFormatBytesPerTexel(vkFmt), mvkVkFormatBytesPerTexel(vkFmt));
+					testFmt(getMTLPixelFormatBytesPerTexel(mtlFmt), mvkMTLPixelFormatBytesPerTexel(mtlFmt));
+					testFmt(getVkFormatBytesPerRow(vkFmt, 4), mvkVkFormatBytesPerRow(vkFmt, 4));
+					testFmt(getMTLPixelFormatBytesPerRow(mtlFmt, 4), mvkMTLPixelFormatBytesPerRow(mtlFmt, 4));
+					testFmt(getVkFormatBytesPerLayer(vkFmt, 256, 4), mvkVkFormatBytesPerLayer(vkFmt, 256, 4));
+					testFmt(getMTLPixelFormatBytesPerLayer(mtlFmt, 256, 4), mvkMTLPixelFormatBytesPerLayer(mtlFmt, 256, 4));
+					testProps(getVkFormatProperties(vkFmt), mvkVkFormatProperties(vkFmt));
+					testFmt(strcmp(getVkFormatName(vkFmt), mvkVkFormatName(vkFmt)), 0);
+					testFmt(strcmp(getMTLPixelFormatName(mtlFmt), mvkMTLPixelFormatName(mtlFmt)), 0);
+					testFmt(getMTLClearColorFromVkClearValue(VkClearValue(), vkFmt),
+							mvkMTLClearColorFromVkClearValue(VkClearValue(), vkFmt));
+
+					testFmt(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageUnknown, mtlFmt),
+							mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageUnknown, mtlFmt));
+					testFmt(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderRead, mtlFmt),
+							mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderRead, mtlFmt));
+					testFmt(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderWrite, mtlFmt),
+							mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageShaderWrite, mtlFmt));
+					testFmt(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageRenderTarget, mtlFmt),
+							mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsageRenderTarget, mtlFmt));
+					testFmt(getVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsagePixelFormatView, mtlFmt),
+							mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsagePixelFormatView, mtlFmt));
+
+					testFmt(getMTLVertexFormatFromVkFormat(vkFmt), mvkMTLVertexFormatFromVkFormat(vkFmt));
+
+#					undef testFmt
+#					undef testProps
+
+				} else {
+					MVKLogInfo("%s not supported or substitutable on this device.", fd.name);
+				}
+			}
+		}
+		MVKLogInfo("Finished testing formats.\n");
+	}
+}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index f3eab2f..9c73c45 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -84,7 +84,7 @@
 	friend class MVKRenderPass;
 	friend class MVKRenderPassAttachment;
 
-	bool isUsingAttachmentAt(uint32_t rpAttIdx);
+	MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx);
 
 	MVKRenderPass* _renderPass;
 	uint32_t _subpassIndex;
@@ -134,8 +134,6 @@
 							const VkAttachmentDescription* pCreateInfo);
 
 protected:
-	VkAttachmentDescription validate(const VkAttachmentDescription* pCreateInfo);
-
 	VkAttachmentDescription _info;
 	MVKRenderPass* _renderPass;
 	uint32_t _attachmentIndex;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 09b8344..ecf02cd 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -197,24 +197,33 @@
 	}
 }
 
-/**
- * Returns whether this subpass uses the attachment at the specified index within the
- * parent renderpass, as any of input, color, resolve, or depth/stencil attachment type.
- */
-bool MVKRenderSubpass::isUsingAttachmentAt(uint32_t rpAttIdx) {
+//Returns the format capabilities required by this render subpass.
+// The Vulkan spec is unclear about whether a subpass can use an attachment in multiple places,
+// so accumulate the capabilities from all possible attachments, just to be safe.
+MVKMTLFmtCaps MVKRenderSubpass::getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx) {
+	MVKMTLFmtCaps caps = kMVKMTLFmtCapsNone;
 
 	for (auto& att : _inputAttachments) {
-		if (att.attachment == rpAttIdx) { return true; }
+		if (att.attachment == rpAttIdx) {
+			mvkEnableFlags(caps, kMVKMTLFmtCapsNone);	// TODO: input attachments are current unsupported
+			break;
+		}
 	}
 	for (auto& att : _colorAttachments) {
-		if (att.attachment == rpAttIdx) { return true; }
+		if (att.attachment == rpAttIdx) {
+			mvkEnableFlags(caps, kMVKMTLFmtCapsColorAtt);
+			break;
+		}
 	}
 	for (auto& att : _resolveAttachments) {
-		if (att.attachment == rpAttIdx) { return true; }
+		if (att.attachment == rpAttIdx) {
+			mvkEnableFlags(caps, kMVKMTLFmtCapsResolve);
+			break;
+		}
 	}
-	if (_depthStencilAttachment.attachment == rpAttIdx) { return true; }
+	if (_depthStencilAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); }
 
-	return false;
+	return caps;
 }
 
 MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
@@ -310,33 +319,35 @@
 
 MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
 												 const VkAttachmentDescription* pCreateInfo) {
+	_info = *pCreateInfo;
 	_renderPass = renderPass;
 	_attachmentIndex = uint32_t(_renderPass->_attachments.size());
 
-	// Determine the indices of the first and last render subpasses to use that attachment.
+	// Validate pixel format is supported
+	MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
+	if ( !pixFmts->vkFormatIsSupportedOrSubstitutable(_info.format) ) {
+		_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s is not supported on this device.", _renderPass->getPixelFormats()->getVkFormatName(_info.format)));
+	}
+
+	// Determine the indices of the first and last render subpasses to use this attachment.
 	_firstUseSubpassIdx = kMVKUndefinedLargeUInt32;
 	_lastUseSubpassIdx = 0;
 	for (auto& subPass : _renderPass->_subpasses) {
-		if (subPass.isUsingAttachmentAt(_attachmentIndex)) {
+		// If it uses this attachment, the subpass will identify required format capabilities.
+		MVKMTLFmtCaps reqCaps = subPass.getRequiredFormatCapabilitiesForAttachmentAt(_attachmentIndex);
+		if (reqCaps) {
 			uint32_t spIdx = subPass._subpassIndex;
-			_firstUseSubpassIdx = MIN(spIdx, _firstUseSubpassIdx);
-			_lastUseSubpassIdx = MAX(spIdx, _lastUseSubpassIdx);
+			_firstUseSubpassIdx = min(spIdx, _firstUseSubpassIdx);
+			_lastUseSubpassIdx = max(spIdx, _lastUseSubpassIdx);
+
+			// Validate that the attachment pixel format supports the capabilities required by the subpass.
+			if ( !mvkAreAllFlagsEnabled(pixFmts->getVkFormatCapabilities(_info.format), reqCaps) ) {
+				_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s on this device does not support the VkFormat attachment capabilities required by the subpass at index %d.", _renderPass->getPixelFormats()->getVkFormatName(_info.format), spIdx));
+			}
 		}
 	}
-
-	_info = validate(pCreateInfo);
 }
 
-// Validate and potentially modify the create info
-VkAttachmentDescription MVKRenderPassAttachment::validate(const VkAttachmentDescription* pCreateInfo) {
-	VkAttachmentDescription info = *pCreateInfo;
-
-	if ( !_renderPass->getPixelFormats()->getMTLPixelFormatFromVkFormat(info.format) ) {
-		_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s is not supported on this device.", _renderPass->getPixelFormats()->getVkFormatName(info.format)));
-	}
-
-	return info;
-}
 
 #pragma mark -
 #pragma mark MVKRenderPass
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
index 2ae2cca..1543d7b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
@@ -503,11 +503,11 @@
     };
 
 	if (mvkAreAllFlagsEnabled(pCreateInfo->flags, VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR)) {
-		mvkEnableFlag(imgInfo.flags, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT);
+		mvkEnableFlags(imgInfo.flags, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT);
 	}
 	if (mvkAreAllFlagsEnabled(pCreateInfo->flags, VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR)) {
 		// We don't really support this, but set the flag anyway.
-		mvkEnableFlag(imgInfo.flags, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT);
+		mvkEnableFlags(imgInfo.flags, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT);
 	}
 
 	_surfaceImages.reserve(imgCnt);
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index e597278..c256bf0 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -20,6 +20,7 @@
 #pragma once
 
 
+#include "MVKCommonEnvironment.h"
 #include "mvk_vulkan.h"
 #include <algorithm>
 #include <string>
@@ -330,6 +331,8 @@
 #pragma mark -
 #pragma mark Template functions
 
+#pragma mark Math
+
 /** Returns whether the value will fit inside the numeric type. */
 template<typename T, typename Tval>
 const bool mvkFits(const Tval& val) {
@@ -349,6 +352,9 @@
 	return (denominator == 1) ? numerator : (numerator + denominator - 1) / denominator;
 }
 
+
+#pragma mark Hashing
+
 /**
  * Returns a hash value calculated from the specified array of numeric elements,
  * using the DJB2a algorithm:  hash = (hash * 33) ^ value.
@@ -364,6 +370,9 @@
     return hash;
 }
 
+
+#pragma mark Containers
+
 /** Ensures the size of the specified container is at least the specified size. */
 template<typename C, typename S>
 void mvkEnsureSize(C& container, S size) {
@@ -416,6 +425,20 @@
     container.erase(remove(container.begin(), container.end(), val), container.end());
 }
 
+
+#pragma mark Values and structs
+
+/** Selects and returns one of the values, based on the platform OS. */
+template<typename T>
+const T& mvkSelectPlatformValue(const T& macOSVal, const T& iOSVal) {
+#if MVK_IOS
+	return iOSVal;
+#endif
+#if MVK_MACOS
+	return macOSVal;
+#endif
+}
+
 /**
  * If pVal is not null, clears the memory occupied by *pVal by writing zeros to all bytes.
  * The optional count allows clearing multiple elements in an array.
@@ -470,39 +493,30 @@
     return false;
 }
 
-/**
- * Enables the flag (set the bit to 1) within the value parameter specified by the bitMask parameter.
- *
- * Typically, you call this function with only a single bit of the bitMask parameter set to 1.
- * However, you may also call this function with more than one bit of the bitMask parameter set
- * to 1, in which case, this function will set all corresponding bits in the value parameter to 1.
- */
-template<typename T1, typename T2>
-void mvkEnableFlag(T1& value, const T2 bitMask) { value |= bitMask; }
 
-/**
- * Disables the flag (set the bit to 0) within the value parameter specified by the bitMask parameter.
- *
- * Typically, you call this function with only a single bit of the bitMask parameter set to 1.
- * However, you may also call this function with more than one bit of the bitMask parameter set
- * to 1, in which case, this function will set all corresponding bits in the value parameter to 0.
- */
-template<typename T1, typename T2>
-void mvkDisableFlag(T1& value, const T2 bitMask) { value &= ~bitMask; }
+#pragma mark Boolean flags
+
+/** Enables the flags (sets bits to 1) within the value parameter specified by the bitMask parameter. */
+template<typename Tv, typename Tm>
+void mvkEnableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value | bitMask); }
+
+/** Disables the flags (sets bits to 0) within the value parameter specified by the bitMask parameter. */
+template<typename Tv, typename Tm>
+void mvkDisableFlags(Tv& value, const Tm bitMask) { value = (Tv)(value & ~(Tv)bitMask); }
 
 /** Returns whether the specified value has ANY of the flags specified in bitMask enabled (set to 1). */
-template<typename T1, typename T2>
-bool mvkIsAnyFlagEnabled(T1 value, const T2 bitMask) { return !!(value & bitMask); }
+template<typename Tv, typename Tm>
+bool mvkIsAnyFlagEnabled(Tv value, const Tm bitMask) { return !!(value & bitMask); }
 
 /** Returns whether the specified value has ALL of the flags specified in bitMask enabled (set to 1). */
-template<typename T1, typename T2>
-bool mvkAreAllFlagsEnabled(T1 value, const T2 bitMask) { return ((value & bitMask) == bitMask); }
+template<typename Tv, typename Tm>
+bool mvkAreAllFlagsEnabled(Tv value, const Tm bitMask) { return ((value & bitMask) == bitMask); }
 
 /** Returns whether the specified value has ONLY one or more of the flags specified in bitMask enabled (set to 1), and none others. */
-template<typename T1, typename T2>
-bool mvkIsOnlyAnyFlagEnabled(T1 value, const T2 bitMask) { return (mvkIsAnyFlagEnabled(value, bitMask) && ((value | bitMask) == bitMask)); }
+template<typename Tv, typename Tm>
+bool mvkIsOnlyAnyFlagEnabled(Tv value, const Tm bitMask) { return (mvkIsAnyFlagEnabled(value, bitMask) && ((value | bitMask) == bitMask)); }
 
 /** Returns whether the specified value has ONLY ALL of the flags specified in bitMask enabled (set to 1), and none others. */
-template<typename T1, typename T2>
-bool mvkAreOnlyAllFlagsEnabled(T1 value, const T2 bitMask) { return (value == bitMask); }
+template<typename Tv, typename Tm>
+bool mvkAreOnlyAllFlagsEnabled(Tv value, const Tm bitMask) { return (value == bitMask); }
 
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
index 4e4be40..be0c519 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
@@ -75,14 +75,6 @@
 #pragma mark -
 #pragma mark Image properties
 
-#pragma mark Texture formats
-
-/**
- * Returns info about the default pixel formats supported by the platform,
- * without taking into consideration support at the MTLDevice level.
- */
-MVKPixelFormats* mvkPlatformPixelFormats();
-
 /** Returns whether 1D textures should be treated as Metal 2D textures with height 1. */
 bool mvkTreatTexture1DAs2D();
 
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
index 19a3250..9b4901f 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
@@ -30,764 +30,113 @@
 using namespace std;
 
 
-#pragma mark -
-#pragma mark Image properties
-
-#define MVK_FMT_IMAGE_FEATS			(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT                    \
-									| VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT                   \
-                                    | VK_FORMAT_FEATURE_BLIT_SRC_BIT                        \
-									| VK_FORMAT_FEATURE_TRANSFER_SRC_BIT                    \
-									| VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
-
-#define MVK_FMT_COLOR_INTEGER_FEATS	(MVK_FMT_IMAGE_FEATS                                    \
-									| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT                \
-									| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT          \
-                                    | VK_FORMAT_FEATURE_BLIT_DST_BIT)
-
-#define MVK_FMT_COLOR_FEATS			(MVK_FMT_COLOR_INTEGER_FEATS | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-
-#if MVK_IOS
-// iOS does not support filtering of float32 values.
-#	define MVK_FMT_COLOR_FLOAT32_FEATS	MVK_FMT_COLOR_INTEGER_FEATS
-#else
-#	define MVK_FMT_COLOR_FLOAT32_FEATS	MVK_FMT_COLOR_FEATS
-#endif
-
-#define MVK_FMT_STENCIL_FEATS		(MVK_FMT_IMAGE_FEATS | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
-
-#if MVK_IOS
-// iOS does not support filtering of depth values.
-#	define MVK_FMT_DEPTH_FEATS		MVK_FMT_STENCIL_FEATS
-#else
-#	define MVK_FMT_DEPTH_FEATS		(MVK_FMT_STENCIL_FEATS | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-#endif
-
-#define MVK_FMT_COMPRESSED_FEATS	(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT                    \
-									| VK_FORMAT_FEATURE_TRANSFER_SRC_BIT                    \
-									| VK_FORMAT_FEATURE_TRANSFER_DST_BIT                    \
-									| VK_FORMAT_FEATURE_BLIT_SRC_BIT                        \
-									| VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-
-#if MVK_MACOS
-// macOS does not support linear images as framebuffer attachments.
-#define MVK_FMT_LINEAR_TILING_FEATS	(MVK_FMT_IMAGE_FEATS | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
-
-// macOS also does not support E5B9G9R9 for anything but filtering.
-#define MVK_FMT_E5B9G9R9_FEATS 		MVK_FMT_COMPRESSED_FEATS
-#else
-#define MVK_FMT_LINEAR_TILING_FEATS	MVK_FMT_COLOR_FEATS
-#define MVK_FMT_E5B9G9R9_FEATS		MVK_FMT_COLOR_FEATS
-#endif
-
-#define MVK_FMT_BUFFER_FEATS		(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT             \
-									| VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
-
-#define MVK_FMT_BUFFER_VTX_FEATS	(MVK_FMT_BUFFER_FEATS | VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
-
-#define MVK_FMT_BUFFER_RDONLY_FEATS	(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)
-
-#if MVK_MACOS
-#define MVK_FMT_E5B9G9R9_BUFFER_FEATS 		MVK_FMT_BUFFER_RDONLY_FEATS
-#else
-#define MVK_FMT_E5B9G9R9_BUFFER_FEATS 		MVK_FMT_BUFFER_FEATS
-#endif
-
-#define MVK_FMT_NO_FEATS			0
-
-#define MVK_MAKE_FMT_STRUCT(VK_FMT, MTL_FMT, MTL_FMT_ALT, IOS_SINCE, MACOS_SINCE, BLK_W, BLK_H, BLK_BYTE_CNT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, VTX_IOS_SINCE, VTX_MACOS_SINCE, CLR_TYPE, PIXEL_FEATS, BUFFER_FEATS)  \
-        { VK_FMT, MTL_FMT, MTL_FMT_ALT, IOS_SINCE, MACOS_SINCE, { BLK_W, BLK_H }, BLK_BYTE_CNT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, VTX_IOS_SINCE, VTX_MACOS_SINCE, CLR_TYPE, { (PIXEL_FEATS & MVK_FMT_LINEAR_TILING_FEATS), PIXEL_FEATS, BUFFER_FEATS }, #VK_FMT, #MTL_FMT, false }
-
-
-#pragma mark Texture formats
+#pragma mark Pixel formats
 
 static MVKPixelFormats _platformPixelFormats;
 
-MVKPixelFormats* mvkPlatformPixelFormats() { return &_platformPixelFormats; }
-
-static const MVKOSVersion kMTLFmtNA = numeric_limits<MVKOSVersion>::max();
-
-/** Describes the properties of each VkFormat, including the corresponding Metal pixel format. */
-typedef struct {
-	VkFormat vk;
-	MTLPixelFormat mtl;
-    MTLPixelFormat mtlSubstitute;
-    MVKOSVersion sinceIOSVersion;
-    MVKOSVersion sinceMacOSVersion;
-    VkExtent2D blockTexelSize;
-	uint32_t bytesPerBlock;
-	MTLVertexFormat mtlVertexFormat;
-	MTLVertexFormat mtlVertexFormatSubstitute;
-	MVKOSVersion vertexSinceIOSVersion;
-	MVKOSVersion vertexSinceMacOSVersion;
-	MVKFormatType formatType;
-	VkFormatProperties properties;
-    const char* vkName;
-    const char* mtlName;
-	bool hasReportedSubstitution;
-
-    inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); };
-
-    inline MVKOSVersion sinceOSVersion() const {
-#if MVK_IOS
-        return sinceIOSVersion;
-#endif
-#if MVK_MACOS
-        return sinceMacOSVersion;
-#endif
-    }
-    inline bool isSupported() const { return (mtl != MTLPixelFormatInvalid) && (mvkOSVersion() >= sinceOSVersion()); };
-    inline bool isSupportedOrSubstitutable() const { return isSupported() || (mtlSubstitute != MTLPixelFormatInvalid); };
-
-    inline MVKOSVersion vertexSinceOSVersion() const {
-#if MVK_IOS
-        return vertexSinceIOSVersion;
-#endif
-#if MVK_MACOS
-        return vertexSinceMacOSVersion;
-#endif
-    }
-    inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid) && (mvkOSVersion() >= vertexSinceOSVersion()); };
-    inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); };
-} MVKPlatformFormatDesc;
-
-/** Mapping between Vulkan and Metal pixel formats. */
-#if MVK_MACOS
-#   define MTLPixelFormatABGR4Unorm             MTLPixelFormatInvalid
-#   define MTLPixelFormatB5G6R5Unorm            MTLPixelFormatInvalid
-#   define MTLPixelFormatA1BGR5Unorm            MTLPixelFormatInvalid
-#   define MTLPixelFormatBGR5A1Unorm            MTLPixelFormatInvalid
-#   define MTLPixelFormatR8Unorm_sRGB           MTLPixelFormatInvalid
-#   define MTLPixelFormatRG8Unorm_sRGB          MTLPixelFormatInvalid
-
-#   define MTLPixelFormatETC2_RGB8              MTLPixelFormatInvalid
-#   define MTLPixelFormatETC2_RGB8_sRGB         MTLPixelFormatInvalid
-#   define MTLPixelFormatETC2_RGB8A1            MTLPixelFormatInvalid
-#   define MTLPixelFormatETC2_RGB8A1_sRGB       MTLPixelFormatInvalid
-#   define MTLPixelFormatEAC_RGBA8              MTLPixelFormatInvalid
-#   define MTLPixelFormatEAC_RGBA8_sRGB         MTLPixelFormatInvalid
-#   define MTLPixelFormatEAC_R11Unorm           MTLPixelFormatInvalid
-#   define MTLPixelFormatEAC_R11Snorm           MTLPixelFormatInvalid
-#   define MTLPixelFormatEAC_RG11Unorm          MTLPixelFormatInvalid
-#   define MTLPixelFormatEAC_RG11Snorm          MTLPixelFormatInvalid
-
-#   define MTLPixelFormatASTC_4x4_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_4x4_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_5x4_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_5x4_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_5x5_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_5x5_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_6x5_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_6x5_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_6x6_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_6x6_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_8x5_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_8x5_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_8x6_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_8x6_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_8x8_LDR           MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_8x8_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x5_LDR          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x5_sRGB         MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x6_LDR          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x6_sRGB         MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x8_LDR          MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x8_sRGB         MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x10_LDR         MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_10x10_sRGB        MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_12x10_LDR         MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_12x10_sRGB        MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_12x12_LDR         MTLPixelFormatInvalid
-#   define MTLPixelFormatASTC_12x12_sRGB        MTLPixelFormatInvalid
-
-#   define MTLPixelFormatPVRTC_RGB_2BPP         MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGB_2BPP_sRGB    MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGB_4BPP         MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGB_4BPP_sRGB    MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGBA_2BPP        MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGBA_2BPP_sRGB   MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGBA_4BPP        MTLPixelFormatInvalid
-#   define MTLPixelFormatPVRTC_RGBA_4BPP_sRGB   MTLPixelFormatInvalid
-
-#   define MTLPixelFormatDepth16Unorm_Stencil8  MTLPixelFormatDepth24Unorm_Stencil8
-#endif
-
-#if MVK_IOS
-#   define MTLPixelFormatDepth16Unorm           MTLPixelFormatInvalid
-#   define MTLPixelFormatDepth24Unorm_Stencil8  MTLPixelFormatInvalid
-#   define MTLPixelFormatBC1_RGBA               MTLPixelFormatInvalid
-#   define MTLPixelFormatBC1_RGBA_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatBC2_RGBA               MTLPixelFormatInvalid
-#   define MTLPixelFormatBC2_RGBA_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatBC3_RGBA               MTLPixelFormatInvalid
-#   define MTLPixelFormatBC3_RGBA_sRGB          MTLPixelFormatInvalid
-#   define MTLPixelFormatBC4_RUnorm             MTLPixelFormatInvalid
-#   define MTLPixelFormatBC4_RSnorm             MTLPixelFormatInvalid
-#   define MTLPixelFormatBC5_RGUnorm            MTLPixelFormatInvalid
-#   define MTLPixelFormatBC5_RGSnorm            MTLPixelFormatInvalid
-#   define MTLPixelFormatBC6H_RGBUfloat         MTLPixelFormatInvalid
-#   define MTLPixelFormatBC6H_RGBFloat          MTLPixelFormatInvalid
-#   define MTLPixelFormatBC7_RGBAUnorm          MTLPixelFormatInvalid
-#   define MTLPixelFormatBC7_RGBAUnorm_sRGB     MTLPixelFormatInvalid
-
-#   define MTLPixelFormatDepth16Unorm_Stencil8  MTLPixelFormatDepth32Float_Stencil8
-#endif
-
-// This cannot be const, because we write to MVKPlatformFormatDesc::hasReportedSubstitution
-static MVKPlatformFormatDesc _formatDescriptions[] {
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_UNDEFINED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 0, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatNone, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R4G4_UNORM_PACK8, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 1, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R4G4B4A4_UNORM_PACK16, MTLPixelFormatABGR4Unorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),	// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B4G4R4A4_UNORM_PACK16, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R5G6B5_UNORM_PACK16, MTLPixelFormatB5G6R5Unorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),	// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B5G6R5_UNORM_PACK16, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R5G5B5A1_UNORM_PACK16, MTLPixelFormatA1BGR5Unorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),	// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B5G5R5A1_UNORM_PACK16, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A1R5G5B5_UNORM_PACK16, MTLPixelFormatBGR5A1Unorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),	// Vulkan packed is reversed
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_UNORM, MTLPixelFormatR8Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 1, MTLVertexFormatUCharNormalized, MTLVertexFormatUChar2Normalized, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_SNORM, MTLPixelFormatR8Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 1, MTLVertexFormatCharNormalized, MTLVertexFormatChar2Normalized, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 1, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 1, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_UINT, MTLPixelFormatR8Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 1, MTLVertexFormatUChar, MTLVertexFormatUChar2, 11.0, 10.13, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_SINT, MTLPixelFormatR8Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 1, MTLVertexFormatChar, MTLVertexFormatChar2, 11.0, 10.13, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8_SRGB, MTLPixelFormatR8Unorm_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 1, 1, 1, MTLVertexFormatUCharNormalized, MTLVertexFormatUChar2Normalized, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_UNORM, MTLPixelFormatRG8Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatUChar2Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_SNORM, MTLPixelFormatRG8Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatChar2Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_UINT, MTLPixelFormatRG8Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatUChar2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_SINT, MTLPixelFormatRG8Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatChar2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8_SRGB, MTLPixelFormatRG8Unorm_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 1, 1, 2, MTLVertexFormatUChar2Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_UNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatUChar3Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatChar3Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatUChar3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatChar3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8_SRGB, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatUChar3Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_UNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorUInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8_SRGB, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_UNORM, MTLPixelFormatRGBA8Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_SNORM, MTLPixelFormatRGBA8Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatChar4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_UINT, MTLPixelFormatRGBA8Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_SINT, MTLPixelFormatRGBA8Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatChar4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R8G8B8A8_SRGB, MTLPixelFormatRGBA8Unorm_sRGB, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_UNORM, MTLPixelFormatBGRA8Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4Normalized_BGRA, MTLVertexFormatInvalid, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorUInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorInt8, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B8G8R8A8_SRGB, MTLPixelFormatBGRA8Unorm_sRGB, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_UNORM_PACK32, MTLPixelFormatRGBA8Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_SNORM_PACK32, MTLPixelFormatRGBA8Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatChar4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_USCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_SSCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_UINT_PACK32, MTLPixelFormatRGBA8Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_SINT_PACK32, MTLPixelFormatRGBA8Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatChar4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt8, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A8B8G8R8_SRGB_PACK32, MTLPixelFormatRGBA8Unorm_sRGB, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUChar4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2R10G10B10_UNORM_PACK32, MTLPixelFormatBGR10A2Unorm, MTLPixelFormatInvalid, 11.0, 10.13, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),	// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2R10G10B10_SNORM_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2R10G10B10_USCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2R10G10B10_SSCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2R10G10B10_UINT_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorUInt16, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2R10G10B10_SINT_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorInt16, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-  
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2B10G10R10_UNORM_PACK32, MTLPixelFormatRGB10A2Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUInt1010102Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),	// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2B10G10R10_SNORM_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInt1010102Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2B10G10R10_USCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2B10G10R10_SSCALED_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2B10G10R10_UINT_PACK32, MTLPixelFormatRGB10A2Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_FEATS ),		// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_A2B10G10R10_SINT_PACK32, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorInt16, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_UNORM, MTLPixelFormatR16Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatUShortNormalized, MTLVertexFormatUShort2Normalized, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_SNORM, MTLPixelFormatR16Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatShortNormalized, MTLVertexFormatShort2Normalized, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_UINT, MTLPixelFormatR16Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatUShort, MTLVertexFormatUShort2, 11.0, 10.13, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_SINT, MTLPixelFormatR16Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatShort, MTLVertexFormatShort2, 11.0, 10.13, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16_SFLOAT, MTLPixelFormatR16Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 2, MTLVertexFormatHalf, MTLVertexFormatHalf2, 11.0, 10.13, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_UNORM, MTLPixelFormatRG16Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUShort2Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_SNORM, MTLPixelFormatRG16Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatShort2Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_UINT, MTLPixelFormatRG16Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUShort2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_SINT, MTLPixelFormatRG16Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatShort2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16_SFLOAT, MTLPixelFormatRG16Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatHalf2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_UNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatUShort3Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_SNORM, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatShort3Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatUShort3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatShort3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 6, MTLVertexFormatHalf3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_UNORM, MTLPixelFormatRGBA16Unorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatUShort4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_SNORM, MTLPixelFormatRGBA16Snorm, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatShort4Normalized, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_USCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_SSCALED, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_UINT, MTLPixelFormatRGBA16Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatUShort4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_SINT, MTLPixelFormatRGBA16Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatShort4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt16, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R16G16B16A16_SFLOAT, MTLPixelFormatRGBA16Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatHalf4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32_UINT, MTLPixelFormatR32Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatUInt, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32_SINT, MTLPixelFormatR32Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatInt, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32_SFLOAT, MTLPixelFormatR32Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatFloat, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32_UINT, MTLPixelFormatRG32Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatUInt2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32_SINT, MTLPixelFormatRG32Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatInt2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32_SFLOAT, MTLPixelFormatRG32Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 8, MTLVertexFormatFloat2, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32B32_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 12, MTLVertexFormatUInt3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32B32_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 12, MTLVertexFormatInt3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32B32_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 12, MTLVertexFormatFloat3, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32B32A32_UINT, MTLPixelFormatRGBA32Uint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 16, MTLVertexFormatUInt4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorUInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32B32A32_SINT, MTLPixelFormatRGBA32Sint, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 16, MTLVertexFormatInt4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorInt32, MVK_FMT_COLOR_INTEGER_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R32G32B32A32_SFLOAT, MTLPixelFormatRGBA32Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 16, MTLVertexFormatFloat4, MTLVertexFormatInvalid, 8.0, 10.11, kMVKFormatColorFloat, MVK_FMT_COLOR_FLOAT32_FEATS, MVK_FMT_BUFFER_VTX_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64B64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 24, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64B64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 24, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64B64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 24, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64B64A64_UINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 32, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64B64A64_SINT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 32, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_R64G64B64A64_SFLOAT, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 1, 1, 32, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_B10G11R11_UFLOAT_PACK32, MTLPixelFormatRG11B10Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),	// Vulkan packed is reversed
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, MTLPixelFormatRGB9E5Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_E5B9G9R9_FEATS, MVK_FMT_E5B9G9R9_BUFFER_FEATS ),	// Vulkan packed is reversed
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_D32_SFLOAT, MTLPixelFormatDepth32Float, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS ),
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_D32_SFLOAT_S8_UINT, MTLPixelFormatDepth32Float_Stencil8, MTLPixelFormatInvalid, 9.0, 10.11, 1, 1, 5, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS ),
-
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_S8_UINT, MTLPixelFormatStencil8, MTLPixelFormatInvalid, 8.0, 10.11, 1, 1, 1, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_STENCIL_FEATS, MVK_FMT_NO_FEATS ),
-
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_D16_UNORM, MTLPixelFormatDepth16Unorm, MTLPixelFormatDepth32Float, kMTLFmtNA, 10.12, 1, 1, 2, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS ),
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_D16_UNORM_S8_UINT, MTLPixelFormatInvalid, MTLPixelFormatDepth16Unorm_Stencil8, kMTLFmtNA, kMTLFmtNA, 1, 1, 3, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS ),
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_D24_UNORM_S8_UINT, MTLPixelFormatDepth24Unorm_Stencil8, MTLPixelFormatDepth32Float_Stencil8, kMTLFmtNA, 10.11, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS ),
-
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_X8_D24_UNORM_PACK32, MTLPixelFormatInvalid, MTLPixelFormatDepth24Unorm_Stencil8, kMTLFmtNA, kMTLFmtNA, 1, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatDepthStencil, MVK_FMT_DEPTH_FEATS, MVK_FMT_NO_FEATS ),	// Vulkan packed is reversed
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC1_RGB_UNORM_BLOCK, MTLPixelFormatBC1_RGBA, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC1_RGB_SRGB_BLOCK, MTLPixelFormatBC1_RGBA_sRGB, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC1_RGBA_UNORM_BLOCK, MTLPixelFormatBC1_RGBA, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC1_RGBA_SRGB_BLOCK, MTLPixelFormatBC1_RGBA_sRGB, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC2_UNORM_BLOCK, MTLPixelFormatBC2_RGBA, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC2_SRGB_BLOCK, MTLPixelFormatBC2_RGBA_sRGB, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC3_UNORM_BLOCK, MTLPixelFormatBC3_RGBA, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC3_SRGB_BLOCK, MTLPixelFormatBC3_RGBA_sRGB, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC4_UNORM_BLOCK, MTLPixelFormatBC4_RUnorm, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC4_SNORM_BLOCK, MTLPixelFormatBC4_RSnorm, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC5_UNORM_BLOCK, MTLPixelFormatBC5_RGUnorm, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC5_SNORM_BLOCK, MTLPixelFormatBC5_RGSnorm, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC6H_UFLOAT_BLOCK, MTLPixelFormatBC6H_RGBUfloat, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC6H_SFLOAT_BLOCK, MTLPixelFormatBC6H_RGBFloat, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC7_UNORM_BLOCK, MTLPixelFormatBC7_RGBAUnorm, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_BC7_SRGB_BLOCK, MTLPixelFormatBC7_RGBAUnorm_sRGB, MTLPixelFormatInvalid, kMTLFmtNA, 10.11, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, MTLPixelFormatETC2_RGB8, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, MTLPixelFormatETC2_RGB8_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, MTLPixelFormatETC2_RGB8A1, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, MTLPixelFormatETC2_RGB8A1_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, MTLPixelFormatEAC_RGBA8, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, MTLPixelFormatEAC_RGBA8_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_EAC_R11_UNORM_BLOCK, MTLPixelFormatEAC_R11Unorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_EAC_R11_SNORM_BLOCK, MTLPixelFormatEAC_R11Snorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_EAC_R11G11_UNORM_BLOCK, MTLPixelFormatEAC_RG11Unorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_EAC_R11G11_SNORM_BLOCK, MTLPixelFormatEAC_RG11Snorm, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_4x4_UNORM_BLOCK, MTLPixelFormatASTC_4x4_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_4x4_SRGB_BLOCK, MTLPixelFormatASTC_4x4_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_5x4_UNORM_BLOCK, MTLPixelFormatASTC_5x4_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 5, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_5x4_SRGB_BLOCK, MTLPixelFormatASTC_5x4_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 5, 4, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_5x5_UNORM_BLOCK, MTLPixelFormatASTC_5x5_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 5, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_5x5_SRGB_BLOCK, MTLPixelFormatASTC_5x5_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 5, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_6x5_UNORM_BLOCK, MTLPixelFormatASTC_6x5_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 6, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_6x5_SRGB_BLOCK, MTLPixelFormatASTC_6x5_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 6, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_6x6_UNORM_BLOCK, MTLPixelFormatASTC_6x6_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 6, 6, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_6x6_SRGB_BLOCK, MTLPixelFormatASTC_6x6_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 6, 6, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_8x5_UNORM_BLOCK, MTLPixelFormatASTC_8x5_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_8x5_SRGB_BLOCK, MTLPixelFormatASTC_8x5_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_8x6_UNORM_BLOCK, MTLPixelFormatASTC_8x6_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 6, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_8x6_SRGB_BLOCK, MTLPixelFormatASTC_8x6_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 6, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_8x8_UNORM_BLOCK, MTLPixelFormatASTC_8x8_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 8, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_8x8_SRGB_BLOCK, MTLPixelFormatASTC_8x8_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 8, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x5_UNORM_BLOCK, MTLPixelFormatASTC_10x5_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x5_SRGB_BLOCK, MTLPixelFormatASTC_10x5_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 5, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x6_UNORM_BLOCK, MTLPixelFormatASTC_10x6_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 6, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x6_SRGB_BLOCK, MTLPixelFormatASTC_10x6_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 6, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x8_UNORM_BLOCK, MTLPixelFormatASTC_10x8_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 8, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x8_SRGB_BLOCK, MTLPixelFormatASTC_10x8_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 8, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x10_UNORM_BLOCK, MTLPixelFormatASTC_10x10_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 10, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_10x10_SRGB_BLOCK, MTLPixelFormatASTC_10x10_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 10, 10, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x10_UNORM_BLOCK, MTLPixelFormatASTC_12x10_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 10, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x10_SRGB_BLOCK, MTLPixelFormatASTC_12x10_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 10, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x12_UNORM_BLOCK, MTLPixelFormatASTC_12x12_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 12, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x12_SRGB_BLOCK, MTLPixelFormatASTC_12x12_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 12, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-
-	// Extension VK_IMG_format_pvrtc
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-	MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
-
-    // Future extension VK_KHX_color_conversion and Vulkan 1.1.
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_UNDEFINED, MTLPixelFormatGBGR422, MTLPixelFormatInvalid, 8.0, 10.11, 2, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-    MVK_MAKE_FMT_STRUCT( VK_FORMAT_UNDEFINED, MTLPixelFormatBGRG422, MTLPixelFormatInvalid, 8.0, 10.11, 2, 1, 4, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatColorFloat, MVK_FMT_COLOR_FEATS, MVK_FMT_BUFFER_FEATS ),
-};
-
-// Map for mapping large VkFormat values to an index.
-typedef unordered_map<uint32_t, uint32_t> MVKFormatIndexByVkFormatMap;
-
-// Vulkan core formats have small values and are mapped by simple lookup array.
-// Vulkan extension formats have larger values and are mapped by a map.
-// MVKFormatIndexByVkFormatMap held as global pointer to allow it to be populated during global init functions.
-static uint16_t _fmtDescIndicesByVkFormatsCore[_vkFormatCoreCount];
-static MVKFormatIndexByVkFormatMap* _pFmtDescIndicesByVkFormatsExt;
-
-// Metal formats have small values and are mapped by simple lookup array.
-static uint16_t _fmtDescIndicesByMTLPixelFormats[_mtlPixelFormatCount];
-static uint16_t _fmtDescIndicesByMTLVertexFormats[_mtlVertexFormatCount];
-
-/**
- * Populates the lookup maps that map Vulkan and Metal pixel formats to one-another.
- *
- * Because both Metal and core Vulkan format value are enumerations that start at zero and are 
- * more or less consecutively enumerated, we can use a simple lookup array in each direction
- * to map the value in one architecture (as an array index) to the corresponding value in the
- * other architecture. Values that exist in one API but not the other are given a default value.
- *
- * Vulkan extension formats have very large values, and are tracked in a separate map.
- */
-static void MVKInitFormatMaps() {
-
-    // Set all VkFormats and MTLPixelFormats to undefined/invalid
-    mvkClear(_fmtDescIndicesByVkFormatsCore, _vkFormatCoreCount);
-    mvkClear(_fmtDescIndicesByMTLPixelFormats, _mtlPixelFormatCount);
-    mvkClear(_fmtDescIndicesByMTLVertexFormats, _mtlVertexFormatCount);
-
-	_pFmtDescIndicesByVkFormatsExt = new MVKFormatIndexByVkFormatMap();
-
-	// Iterate through the format descriptions and populate the lookup maps.
-	uint32_t fmtCnt = sizeof(_formatDescriptions) / sizeof(MVKPlatformFormatDesc);
-	for (uint32_t fmtIdx = 0; fmtIdx < fmtCnt; fmtIdx++) {
-
-		// Access the mapping
-		const MVKPlatformFormatDesc& tfm = _formatDescriptions[fmtIdx];
-
-		// If the Vulkan format is defined, create a lookup between the Vulkan format
-        // and an index to the format info. For core Vulkan formats, which are small
-        // and consecutive, use a simple lookup array. For extension formats, use a map.
-        if (tfm.vk != VK_FORMAT_UNDEFINED) {
-            if (tfm.vk < _vkFormatCoreCount) {
-                _fmtDescIndicesByVkFormatsCore[tfm.vk] = fmtIdx;
-            } else {
-				(*_pFmtDescIndicesByVkFormatsExt)[tfm.vk] = fmtIdx;
-            }
-        }
-
-        // If the Metal format is defined, create a lookup between the Metal format and an
-        // index to the format info. Metal formats are small, so use a simple lookup array.
-		if (tfm.mtl != MTLPixelFormatInvalid && !_fmtDescIndicesByMTLPixelFormats[tfm.mtl]) {
-			_fmtDescIndicesByMTLPixelFormats[tfm.mtl] = fmtIdx;
-		}
-		if (tfm.mtlVertexFormat != MTLVertexFormatInvalid && !_fmtDescIndicesByMTLVertexFormats[tfm.mtlVertexFormat]) {
-			_fmtDescIndicesByMTLVertexFormats[tfm.mtlVertexFormat] = fmtIdx;
-		}
-	}
-}
-
-// Return a reference to the format description corresponding to the VkFormat.
-inline const MVKPlatformFormatDesc& formatDescForVkFormat(VkFormat vkFormat) {
-	uint16_t fmtIdx = (vkFormat < _vkFormatCoreCount) ? _fmtDescIndicesByVkFormatsCore[vkFormat] : (*_pFmtDescIndicesByVkFormatsExt)[vkFormat];
-    return _formatDescriptions[fmtIdx];
-}
-
-// Return a reference to the format description corresponding to the MTLPixelFormat.
-inline const MVKPlatformFormatDesc& formatDescForMTLPixelFormat(MTLPixelFormat mtlFormat) {
-    uint16_t fmtIdx = (mtlFormat < _mtlPixelFormatCount) ? _fmtDescIndicesByMTLPixelFormats[mtlFormat] : 0;
-    return _formatDescriptions[fmtIdx];
-}
-
-// Return a reference to the format description corresponding to the MTLVertexFormat.
-inline const MVKPlatformFormatDesc& formatDescForMTLVertexFormat(MTLVertexFormat mtlFormat) {
-    uint16_t fmtIdx = (mtlFormat < _mtlVertexFormatCount) ? _fmtDescIndicesByMTLVertexFormats[mtlFormat] : 0;
-    return _formatDescriptions[fmtIdx];
-}
-
 MVK_PUBLIC_SYMBOL bool mvkVkFormatIsSupported(VkFormat vkFormat) {
-	return formatDescForVkFormat(vkFormat).isSupported();
+	return _platformPixelFormats.vkFormatIsSupported(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL bool mvkMTLPixelFormatIsSupported(MTLPixelFormat mtlFormat) {
-	return formatDescForMTLPixelFormat(mtlFormat).isSupported();
+	return _platformPixelFormats.mtlPixelFormatIsSupported(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL MVKFormatType mvkFormatTypeFromVkFormat(VkFormat vkFormat) {
-	return formatDescForVkFormat(vkFormat).formatType;
+	return _platformPixelFormats.getFormatTypeFromVkFormat(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL MVKFormatType mvkFormatTypeFromMTLPixelFormat(MTLPixelFormat mtlFormat) {
-	return formatDescForMTLPixelFormat(mtlFormat).formatType;
+	return _platformPixelFormats.getFormatTypeFromMTLPixelFormat(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL MTLPixelFormat mvkMTLPixelFormatFromVkFormat(VkFormat vkFormat) {
-	MTLPixelFormat mtlPixFmt = MTLPixelFormatInvalid;
-
-	const MVKPlatformFormatDesc& fmtDesc = formatDescForVkFormat(vkFormat);
-	if (fmtDesc.isSupported()) {
-		mtlPixFmt = fmtDesc.mtl;
-	} else if (vkFormat != VK_FORMAT_UNDEFINED) {
-		// If the MTLPixelFormat is not supported but VkFormat is valid, attempt to substitute a different format.
-		mtlPixFmt = fmtDesc.mtlSubstitute;
-
-		// Report an error if there is no substitute, or the first time a substitution is made.
-		if ( !mtlPixFmt || !fmtDesc.hasReportedSubstitution ) {
-			string errMsg;
-			errMsg += "VkFormat ";
-			errMsg += (fmtDesc.vkName) ? fmtDesc.vkName : to_string(fmtDesc.vk);
-			errMsg += " is not supported on this device.";
-
-			if (mtlPixFmt) {
-				((MVKPlatformFormatDesc*)&fmtDesc)->hasReportedSubstitution = true;
-
-				const MVKPlatformFormatDesc& fmtDescSubs = formatDescForMTLPixelFormat(mtlPixFmt);
-				errMsg += " Using VkFormat ";
-				errMsg += (fmtDescSubs.vkName) ? fmtDescSubs.vkName : to_string(fmtDescSubs.vk);
-				errMsg += " instead.";
-			}
-			MVKBaseObject::reportError(nullptr, VK_ERROR_FORMAT_NOT_SUPPORTED, "%s", errMsg.c_str());
-		}
-	}
-
-	return mtlPixFmt;
+	return _platformPixelFormats.getMTLPixelFormatFromVkFormat(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL VkFormat mvkVkFormatFromMTLPixelFormat(MTLPixelFormat mtlFormat) {
-    return formatDescForMTLPixelFormat(mtlFormat).vk;
+	return _platformPixelFormats.getVkFormatFromMTLPixelFormat(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL uint32_t mvkVkFormatBytesPerBlock(VkFormat vkFormat) {
-    return formatDescForVkFormat(vkFormat).bytesPerBlock;
+	return _platformPixelFormats.getVkFormatBytesPerBlock(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL uint32_t mvkMTLPixelFormatBytesPerBlock(MTLPixelFormat mtlFormat) {
-    return formatDescForMTLPixelFormat(mtlFormat).bytesPerBlock;
+	return _platformPixelFormats.getMTLPixelFormatBytesPerBlock(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL VkExtent2D mvkVkFormatBlockTexelSize(VkFormat vkFormat) {
-    return formatDescForVkFormat(vkFormat).blockTexelSize;
+	return _platformPixelFormats.getVkFormatBlockTexelSize(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL VkExtent2D mvkMTLPixelFormatBlockTexelSize(MTLPixelFormat mtlFormat) {
-    return formatDescForMTLPixelFormat(mtlFormat).blockTexelSize;
+	return _platformPixelFormats.getMTLPixelFormatBlockTexelSize(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL float mvkVkFormatBytesPerTexel(VkFormat vkFormat) {
-    return formatDescForVkFormat(vkFormat).bytesPerTexel();
+	return _platformPixelFormats.getVkFormatBytesPerTexel(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL float mvkMTLPixelFormatBytesPerTexel(MTLPixelFormat mtlFormat) {
-    return formatDescForMTLPixelFormat(mtlFormat).bytesPerTexel();
+	return _platformPixelFormats.getMTLPixelFormatBytesPerTexel(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL size_t mvkVkFormatBytesPerRow(VkFormat vkFormat, uint32_t texelsPerRow) {
-    const MVKPlatformFormatDesc& fmtDesc = formatDescForVkFormat(vkFormat);
-    return mvkCeilingDivide(texelsPerRow, fmtDesc.blockTexelSize.width) * fmtDesc.bytesPerBlock;
+	return _platformPixelFormats.getVkFormatBytesPerRow(vkFormat, texelsPerRow);
 }
 
 MVK_PUBLIC_SYMBOL size_t mvkMTLPixelFormatBytesPerRow(MTLPixelFormat mtlFormat, uint32_t texelsPerRow) {
-    const MVKPlatformFormatDesc& fmtDesc = formatDescForMTLPixelFormat(mtlFormat);
-    return mvkCeilingDivide(texelsPerRow, fmtDesc.blockTexelSize.width) * fmtDesc.bytesPerBlock;
+	return _platformPixelFormats.getMTLPixelFormatBytesPerRow(mtlFormat, texelsPerRow);
 }
 
 MVK_PUBLIC_SYMBOL size_t mvkVkFormatBytesPerLayer(VkFormat vkFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer) {
-    return mvkCeilingDivide(texelRowsPerLayer, formatDescForVkFormat(vkFormat).blockTexelSize.height) * bytesPerRow;
+	return _platformPixelFormats.getVkFormatBytesPerLayer(vkFormat, bytesPerRow, texelRowsPerLayer);
 }
 
 MVK_PUBLIC_SYMBOL size_t mvkMTLPixelFormatBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer) {
-    return mvkCeilingDivide(texelRowsPerLayer, formatDescForMTLPixelFormat(mtlFormat).blockTexelSize.height) * bytesPerRow;
+	return _platformPixelFormats.getMTLPixelFormatBytesPerLayer(mtlFormat, bytesPerRow, texelRowsPerLayer);
 }
 
-MVK_PUBLIC_SYMBOL VkFormatProperties mvkVkFormatProperties(VkFormat vkFormat, bool assumeGPUSupportsDefault) {
-	VkFormatProperties fmtProps = {MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS};
-	const MVKPlatformFormatDesc& fmtDesc = formatDescForVkFormat(vkFormat);
-	if (assumeGPUSupportsDefault && fmtDesc.isSupported()) {
-		fmtProps = fmtDesc.properties;
-		if (!fmtDesc.vertexIsSupportedOrSubstitutable()) {
-			fmtProps.bufferFeatures &= ~VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
-		}
-	} else {
-		// If texture format is unsupported, vertex buffer format may still be.
-		fmtProps.bufferFeatures |= fmtDesc.properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
-	}
-	return fmtProps;
+MVK_PUBLIC_SYMBOL VkFormatProperties mvkVkFormatProperties(VkFormat vkFormat) {
+	return _platformPixelFormats.getVkFormatProperties(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL const char* mvkVkFormatName(VkFormat vkFormat) {
-    return formatDescForVkFormat(vkFormat).vkName;
+	return _platformPixelFormats.getVkFormatName(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL const char* mvkMTLPixelFormatName(MTLPixelFormat mtlFormat) {
-    return formatDescForMTLPixelFormat(mtlFormat).mtlName;
+	return _platformPixelFormats.getMTLPixelFormatName(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL MTLVertexFormat mvkMTLVertexFormatFromVkFormat(VkFormat vkFormat) {
-    MTLVertexFormat mtlVtxFmt = MTLVertexFormatInvalid;
-    const MVKPlatformFormatDesc& fmtDesc = formatDescForVkFormat(vkFormat);
-    if (fmtDesc.vertexIsSupported()) {
-        mtlVtxFmt = fmtDesc.mtlVertexFormat;
-    } else if (vkFormat != VK_FORMAT_UNDEFINED) {
-        // If the MTLVertexFormat is not supported but VkFormat is valid,
-        // report an error, and possibly substitute a different MTLVertexFormat.
-        string errMsg;
-        errMsg += "VkFormat ";
-        errMsg += (fmtDesc.vkName) ? fmtDesc.vkName : to_string(fmtDesc.vk);
-        errMsg += " is not supported for vertex buffers on this device.";
-
-        if (fmtDesc.vertexIsSupportedOrSubstitutable()) {
-            mtlVtxFmt = fmtDesc.mtlVertexFormatSubstitute;
-
-            const MVKPlatformFormatDesc& fmtDescSubs = formatDescForMTLVertexFormat(mtlVtxFmt);
-            errMsg += " Using VkFormat ";
-            errMsg += (fmtDescSubs.vkName) ? fmtDescSubs.vkName : to_string(fmtDescSubs.vk);
-            errMsg += " instead.";
-        }
-		MVKBaseObject::reportError(nullptr, VK_ERROR_FORMAT_NOT_SUPPORTED, "%s", errMsg.c_str());
-    }
-
-    return mtlVtxFmt;
+	return _platformPixelFormats.getMTLVertexFormatFromVkFormat(vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL MTLClearColor mvkMTLClearColorFromVkClearValue(VkClearValue vkClearValue,
 																 VkFormat vkFormat) {
-	MTLClearColor mtlClr;
-	switch (mvkFormatTypeFromVkFormat(vkFormat)) {
-		case kMVKFormatColorHalf:
-		case kMVKFormatColorFloat:
-			mtlClr.red		= vkClearValue.color.float32[0];
-			mtlClr.green	= vkClearValue.color.float32[1];
-			mtlClr.blue		= vkClearValue.color.float32[2];
-			mtlClr.alpha	= vkClearValue.color.float32[3];
-			break;
-		case kMVKFormatColorUInt8:
-		case kMVKFormatColorUInt16:
-		case kMVKFormatColorUInt32:
-			mtlClr.red		= vkClearValue.color.uint32[0];
-			mtlClr.green	= vkClearValue.color.uint32[1];
-			mtlClr.blue		= vkClearValue.color.uint32[2];
-			mtlClr.alpha	= vkClearValue.color.uint32[3];
-			break;
-		case kMVKFormatColorInt8:
-		case kMVKFormatColorInt16:
-		case kMVKFormatColorInt32:
-			mtlClr.red		= vkClearValue.color.int32[0];
-			mtlClr.green	= vkClearValue.color.int32[1];
-			mtlClr.blue		= vkClearValue.color.int32[2];
-			mtlClr.alpha	= vkClearValue.color.int32[3];
-			break;
-		default:
-			mtlClr.red		= 0.0;
-			mtlClr.green	= 0.0;
-			mtlClr.blue		= 0.0;
-			mtlClr.alpha	= 1.0;
-			break;
-	}
-	return mtlClr;
+	return _platformPixelFormats.getMTLClearColorFromVkClearValue(vkClearValue, vkFormat);
 }
 
 MVK_PUBLIC_SYMBOL double mvkMTLClearDepthFromVkClearValue(VkClearValue vkClearValue) {
-	return vkClearValue.depthStencil.depth;
+	return _platformPixelFormats.getMTLClearDepthFromVkClearValue(vkClearValue);
 }
 
 MVK_PUBLIC_SYMBOL uint32_t mvkMTLClearStencilFromVkClearValue(VkClearValue vkClearValue) {
-	return vkClearValue.depthStencil.stencil;
+	return _platformPixelFormats.getMTLClearStencilFromVkClearValue(vkClearValue);
 }
 
 MVK_PUBLIC_SYMBOL bool mvkMTLPixelFormatIsDepthFormat(MTLPixelFormat mtlFormat) {
-	switch (mtlFormat) {
-		case MTLPixelFormatDepth32Float:
-#if MVK_MACOS
-        case MTLPixelFormatDepth16Unorm:
-		case MTLPixelFormatDepth24Unorm_Stencil8:
-#endif
-		case MTLPixelFormatDepth32Float_Stencil8:
-			return true;
-		default:
-			return false;
-	}
+	return _platformPixelFormats.mtlPixelFormatIsDepthFormat(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL bool mvkMTLPixelFormatIsStencilFormat(MTLPixelFormat mtlFormat) {
-	switch (mtlFormat) {
-		case MTLPixelFormatStencil8:
-#if MVK_MACOS
-		case MTLPixelFormatDepth24Unorm_Stencil8:
-        case MTLPixelFormatX24_Stencil8:
-#endif
-		case MTLPixelFormatDepth32Float_Stencil8:
-        case MTLPixelFormatX32_Stencil8:
-			return true;
-		default:
-			return false;
-	}
+	return _platformPixelFormats.mtlPixelFormatIsStencilFormat(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL bool mvkMTLPixelFormatIsPVRTCFormat(MTLPixelFormat mtlFormat) {
-	switch (mtlFormat) {
-#if MVK_IOS
-		case MTLPixelFormatPVRTC_RGBA_2BPP:
-		case MTLPixelFormatPVRTC_RGBA_2BPP_sRGB:
-		case MTLPixelFormatPVRTC_RGBA_4BPP:
-		case MTLPixelFormatPVRTC_RGBA_4BPP_sRGB:
-		case MTLPixelFormatPVRTC_RGB_2BPP:
-		case MTLPixelFormatPVRTC_RGB_2BPP_sRGB:
-		case MTLPixelFormatPVRTC_RGB_4BPP:
-		case MTLPixelFormatPVRTC_RGB_4BPP_sRGB:
-			return true;
-#endif
-		default:
-			return false;
-	}
+	return _platformPixelFormats.mtlPixelFormatIsPVRTCFormat(mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType,
@@ -850,19 +199,19 @@
 												VK_IMAGE_USAGE_SAMPLED_BIT |
 												VK_IMAGE_USAGE_STORAGE_BIT |
 												VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) {
-		mvkEnableFlag(mtlUsage, MTLTextureUsageShaderRead);
+		mvkEnableFlags(mtlUsage, MTLTextureUsageShaderRead);
 	}
 
 	// Write to...
 	if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_STORAGE_BIT))) {
-		mvkEnableFlag(mtlUsage, MTLTextureUsageShaderWrite);
+		mvkEnableFlags(mtlUsage, MTLTextureUsageShaderWrite);
 	}
 
 	// Render to...
 	if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
 												VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
 												VK_IMAGE_USAGE_TRANSFER_DST_BIT))) {				// Scaling a BLIT may use rendering.
-		mvkEnableFlag(mtlUsage, MTLTextureUsageRenderTarget);
+		mvkEnableFlags(mtlUsage, MTLTextureUsageRenderTarget);
 	}
 
 	// Create view on...
@@ -872,33 +221,14 @@
 												VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
 												VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
 												VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))) {	// D/S may be filtered out after device check
-		mvkEnableFlag(mtlUsage, MTLTextureUsagePixelFormatView);
+		mvkEnableFlags(mtlUsage, MTLTextureUsagePixelFormatView);
 	}
 
     return mtlUsage;
 }
 
 MVK_PUBLIC_SYMBOL VkImageUsageFlags mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsage mtlUsage, MTLPixelFormat mtlFormat) {
-    VkImageUsageFlags vkImageUsageFlags = 0;
-
-    if ( mvkAreAllFlagsEnabled(mtlUsage, MTLTextureUsageShaderRead) ) {
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_SAMPLED_BIT);
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
-    }
-    if ( mvkAreAllFlagsEnabled(mtlUsage, MTLTextureUsageRenderTarget) ) {
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_TRANSFER_DST_BIT);
-        if (mvkMTLPixelFormatIsDepthFormat(mtlFormat) || mvkMTLPixelFormatIsStencilFormat(mtlFormat)) {
-            mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
-        } else {
-            mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
-        }
-    }
-    if ( mvkAreAllFlagsEnabled(mtlUsage, MTLTextureUsageShaderWrite) ) {
-        mvkEnableFlag(vkImageUsageFlags, VK_IMAGE_USAGE_STORAGE_BIT);
-    }
-
-    return vkImageUsageFlags;
+	return _platformPixelFormats.getVkImageUsageFlagsFromMTLTextureUsage(mtlUsage, mtlFormat);
 }
 
 MVK_PUBLIC_SYMBOL uint32_t mvkSampleCountFromVkSampleCountFlagBits(VkSampleCountFlagBits vkSampleCountFlag) {
@@ -1029,10 +359,10 @@
 
 MVK_PUBLIC_SYMBOL MTLColorWriteMask mvkMTLColorWriteMaskFromVkChannelFlags(VkColorComponentFlags vkWriteFlags) {
 	MTLColorWriteMask mtlWriteMask = MTLColorWriteMaskNone;
-	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_R_BIT)) { mvkEnableFlag(mtlWriteMask, MTLColorWriteMaskRed); }
-	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_G_BIT)) { mvkEnableFlag(mtlWriteMask, MTLColorWriteMaskGreen); }
-	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_B_BIT)) { mvkEnableFlag(mtlWriteMask, MTLColorWriteMaskBlue); }
-	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_A_BIT)) { mvkEnableFlag(mtlWriteMask, MTLColorWriteMaskAlpha); }
+	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_R_BIT)) { mvkEnableFlags(mtlWriteMask, MTLColorWriteMaskRed); }
+	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_G_BIT)) { mvkEnableFlags(mtlWriteMask, MTLColorWriteMaskGreen); }
+	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_B_BIT)) { mvkEnableFlags(mtlWriteMask, MTLColorWriteMaskBlue); }
+	if (mvkAreAllFlagsEnabled(vkWriteFlags, VK_COLOR_COMPONENT_A_BIT)) { mvkEnableFlags(mtlWriteMask, MTLColorWriteMaskAlpha); }
 	return mtlWriteMask;
 }
 
@@ -1437,22 +767,3 @@
 	return _mvkTexture1DAs2D;
 }
 
-
-#pragma mark -
-#pragma mark Library initialization
-
-/**
- * Called automatically when the framework is loaded and initialized.
- *
- * Initialize various data type lookups.
- */
-static bool _mvkDataTypesInitialized = false;
-__attribute__((constructor)) static void MVKInitDataTypes() {
-	if (_mvkDataTypesInitialized ) { return; }
-	_mvkDataTypesInitialized = true;
-
-	MVKInitFormatMaps();
-}
-
-	
-
diff --git a/MoltenVKPackaging.xcodeproj/project.pbxproj b/MoltenVKPackaging.xcodeproj/project.pbxproj
index 7598811..776b6cf 100644
--- a/MoltenVKPackaging.xcodeproj/project.pbxproj
+++ b/MoltenVKPackaging.xcodeproj/project.pbxproj
@@ -248,7 +248,7 @@
 		A90B2B1D1A9B6170008EE819 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 				TargetAttributes = {
 					A9FEADBC1F3517480010240E = {
 						DevelopmentTeam = VU3TCKU48B;
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
index 91cc9a2..c68daf5 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
index 5c76128..5d5ea44 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
index ea0cde8..011bb1f 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
index 9d862a0..0e1d409 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "NO"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
index 285dccb..e5a091c 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
@@ -415,7 +415,7 @@
 		A9F55D25198BE6A7004EC31B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1130;
+				LastUpgradeCheck = 1140;
 				ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
 				TargetAttributes = {
 					A9092A8C1A81717B00051823 = {
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
index 078a2bb..9c5e88e 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
index c89ef49..555a788 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
index d2f230a..a3d1947 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
index 5b630c7..445228e 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
index 2172574..9b5bad7 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1130"
+   LastUpgradeVersion = "1140"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"