Merge pull request #1015 from cdavis5e/vulkan1.1

Support Vulkan 1.1.
diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h
index 4fe27b4..99e5b88 100644
--- a/Common/MVKCommonEnvironment.h
+++ b/Common/MVKCommonEnvironment.h
@@ -75,6 +75,9 @@
 /** Directive to identify public symbols. */
 #define MVK_PUBLIC_SYMBOL        __attribute__((visibility("default")))
 
+/** Directive to make a public alias of another symbol. */
+#define MVK_PUBLIC_ALIAS(a, t)   asm(".globl _" #a "; _" #a " = _" #t "\n")
+
 
 #ifdef __cplusplus
 }
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 199099f..b03c059 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -53,7 +53,7 @@
 About **MoltenVK**
 ------------------
 
-**MoltenVK** is a layered implementation of [*Vulkan 1.0*](https://www.khronos.org/vulkan) 
+**MoltenVK** is a layered implementation of [*Vulkan 1.1*](https://www.khronos.org/vulkan) 
 graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal) 
 graphics and compute framework on *macOS*, *iOS*, and *tvOS*. **MoltenVK** allows you to use *Vulkan* 
 graphics and compute functionality to develop modern, cross-platform, high-performance graphical games 
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 54307db..68d6acd 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -18,6 +18,12 @@
 
 Released TBD
 
+- Add support for Vulkan 1.1, including:
+	- The `vkEnumerateInstanceVersion()` function
+	- The `vkGetDeviceQueue2()` function
+	- Protected memory (non-functional)
+	- A feature struct for `VK_KHR_shader_draw_parameters`
+	- All extensions that were promoted to core in Vulkan 1.1
 - Add support for extensions:
 	- `VK_KHR_external_fence` (non-functional groundwork for future extensions,
 	  including support for GCD and Mach semaphores)
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index ed4896f..03560d1 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -17,6 +17,7 @@
  */
 
 #include "MVKDescriptorSet.h"
+#include "MVKInstance.h"
 #include "MVKOSExtensions.h"
 
 
@@ -554,7 +555,8 @@
 												   const VkDescriptorSetLayout* pSetLayouts,
 												   VkDescriptorSet* pDescriptorSets) {
 	if (_allocatedSets.size() + count > _maxSets) {
-		if (_device->_enabledExtensions.vk_KHR_maintenance1.enabled) {
+		if (_device->_enabledExtensions.vk_KHR_maintenance1.enabled ||
+			_device->getInstance()->getAPIVersion() >= VK_API_VERSION_1_1) {
 			return VK_ERROR_OUT_OF_POOL_MEMORY;		// Failure is an acceptable test...don't log as error.
 		} else {
 			return reportError(VK_ERROR_INITIALIZATION_FAILED, "The maximum number of descriptor sets that can be allocated by this descriptor pool is %d.", _maxSets);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index 9e78715..c1062d0 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -426,6 +426,9 @@
 	/** Returns the queue at the specified index within the specified family. */
 	MVKQueue* getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex);
 
+	/** Returns the queue described by the specified structure. */
+	MVKQueue* getQueue(const VkDeviceQueueInfo2* queueInfo);
+
 	/** Retrieves the queue at the lowest queue and queue family indices used by the app. */
 	MVKQueue* getAnyQueue();
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 71fb97d..18c7899 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -98,6 +98,21 @@
 				multiviewFeatures->multiviewTessellationShader = false; // FIXME
 				break;
 			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: {
+				auto* protectedMemFeatures = (VkPhysicalDeviceProtectedMemoryFeatures*)next;
+				protectedMemFeatures->protectedMemory = false;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
+				auto* samplerYcbcrConvFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)next;
+				samplerYcbcrConvFeatures->samplerYcbcrConversion = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: {
+				auto* shaderDrawParamsFeatures = (VkPhysicalDeviceShaderDrawParametersFeatures*)next;
+				shaderDrawParamsFeatures->shaderDrawParameters = true;
+				break;
+			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
 				auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next;
 				uboLayoutFeatures->uniformBufferStandardLayout = true;
@@ -158,11 +173,6 @@
 				portabilityFeatures->samplerMipLodBias = false;
 				break;
 			}
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
-				auto* samplerYcbcrConvFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)next;
-				samplerYcbcrConvFeatures->samplerYcbcrConversion = true;
-				break;
-			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: {
 				auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next;
 				shaderIntFuncsFeatures->shaderIntegerFunctions2 = true;
@@ -189,9 +199,19 @@
 	properties->properties = _properties;
 	for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
 		switch ((uint32_t)next->sType) {
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
-				auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
-				pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: {
+				auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next;
+				strcpy(physicalDeviceDriverProps->driverName, "MoltenVK");
+				strcpy(physicalDeviceDriverProps->driverInfo, mvkGetMoltenVKVersionString(MVK_VERSION).c_str());
+				physicalDeviceDriverProps->driverID = VK_DRIVER_ID_MOLTENVK;
+				physicalDeviceDriverProps->conformanceVersion.major = 0;
+				physicalDeviceDriverProps->conformanceVersion.minor = 0;
+				physicalDeviceDriverProps->conformanceVersion.subminor = 0;
+				physicalDeviceDriverProps->conformanceVersion.patch = 0;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
+				populate((VkPhysicalDeviceIDProperties*)next);
 				break;
 			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
@@ -210,51 +230,21 @@
                 }
 				break;
             }
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
+				auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
+				pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: {
+				auto* protectedMemProps = (VkPhysicalDeviceProtectedMemoryProperties*)next;
+				protectedMemProps->protectedNoFault = false;
+				break;
+			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
 				auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
 				pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
 				break;
 			}
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
-				auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next;
-				// This isn't implemented yet, but when it is, I expect that we'll wind up
-				// doing it manually.
-				robustness2Props->robustStorageBufferAccessSizeAlignment = 1;
-				robustness2Props->robustUniformBufferAccessSizeAlignment = 1;
-				break;
-			}
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
-				auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
-				// Save the 'next' pointer; we'll unintentionally overwrite it
-				// on the next line. Put it back when we're done.
-				void* savedNext = texelBuffAlignProps->pNext;
-				*texelBuffAlignProps = _texelBuffAlignProperties;
-				texelBuffAlignProps->pNext = savedNext;
-				break;
-			}
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
-				auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
-				divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
-				break;
-			}
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
-				populate((VkPhysicalDeviceIDProperties*)next);
-				break;
-			}
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
-				auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
-				portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
-				break;
-			}
-            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: {
-				auto* inlineUniformBlockProps = (VkPhysicalDeviceInlineUniformBlockPropertiesEXT*)next;
-				inlineUniformBlockProps->maxInlineUniformBlockSize = _metalFeatures.dynamicMTLBufferSize;
-                inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
-                inlineUniformBlockProps->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
-                inlineUniformBlockProps->maxDescriptorSetInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
-                inlineUniformBlockProps->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
-				break;
-			}
 #if MVK_MACOS
             case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES:
                 if (mvkOSVersionIsAtLeast(10.14)) {
@@ -277,15 +267,40 @@
                 }
 				break;
 #endif
-			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: {
-				auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next;
-				strcpy(physicalDeviceDriverProps->driverName, "MoltenVK");
-				strcpy(physicalDeviceDriverProps->driverInfo, mvkGetMoltenVKVersionString(MVK_VERSION).c_str());
-				physicalDeviceDriverProps->driverID = VK_DRIVER_ID_MOLTENVK;
-				physicalDeviceDriverProps->conformanceVersion.major = 0;
-				physicalDeviceDriverProps->conformanceVersion.minor = 0;
-				physicalDeviceDriverProps->conformanceVersion.subminor = 0;
-				physicalDeviceDriverProps->conformanceVersion.patch = 0;
+            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: {
+				auto* inlineUniformBlockProps = (VkPhysicalDeviceInlineUniformBlockPropertiesEXT*)next;
+				inlineUniformBlockProps->maxInlineUniformBlockSize = _metalFeatures.dynamicMTLBufferSize;
+                inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
+                inlineUniformBlockProps->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
+                inlineUniformBlockProps->maxDescriptorSetInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
+                inlineUniformBlockProps->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
+				auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next;
+				// This isn't implemented yet, but when it is, I expect that we'll wind up
+				// doing it manually.
+				robustness2Props->robustStorageBufferAccessSizeAlignment = 1;
+				robustness2Props->robustUniformBufferAccessSizeAlignment = 1;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
+				auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
+				// Save the 'next' pointer; we'll unintentionally overwrite it
+				// on the next line. Put it back when we're done.
+				void* savedNext = texelBuffAlignProps->pNext;
+				*texelBuffAlignProps = _texelBuffAlignProperties;
+				texelBuffAlignProps->pNext = savedNext;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
+				auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
+				divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
+				auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
+				portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
 				break;
 			}
 			default:
@@ -2367,10 +2382,11 @@
 // Returns core device commands and enabled extension device commands.
 PFN_vkVoidFunction MVKDevice::getProcAddr(const char* pName) {
 	MVKEntryPoint* pMVKPA = _physicalDevice->_mvkInstance->getEntryPoint(pName);
+	uint32_t apiVersion = _physicalDevice->_mvkInstance->_appInfo.apiVersion;
 
-	bool isSupported = (pMVKPA &&								// Command exists and...
-						pMVKPA->isDevice &&						// ...is a device command and...
-						pMVKPA->isEnabled(_enabledExtensions));	// ...is a core or enabled extension command.
+	bool isSupported = (pMVKPA &&											// Command exists and...
+						pMVKPA->isDevice &&									// ...is a device command and...
+						pMVKPA->isEnabled(apiVersion, _enabledExtensions));	// ...is a core or enabled extension command.
 
 	return isSupported ? pMVKPA->functionPointer : nullptr;
 }
@@ -2379,6 +2395,10 @@
 	return _queuesByQueueFamilyIndex[queueFamilyIndex][queueIndex];
 }
 
+MVKQueue* MVKDevice::getQueue(const VkDeviceQueueInfo2* queueInfo) {
+	return _queuesByQueueFamilyIndex[queueInfo->queueFamilyIndex][queueInfo->queueIndex];
+}
+
 MVKQueue* MVKDevice::getAnyQueue() {
 	for (auto& queues : _queuesByQueueFamilyIndex) {
 		for (MVKQueue* q : queues) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
index 6195691..3ff1a95 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
@@ -37,13 +37,15 @@
 /** Tracks info about entry point function pointer addresses. */
 typedef struct {
 	PFN_vkVoidFunction functionPointer;
+	uint32_t apiVersion;
 	const char* ext1Name;
 	const char* ext2Name;
 	bool isDevice;
 
 	bool isCore() { return !ext1Name && !ext2Name; }
-	bool isEnabled(const MVKExtensionList& extList) {
-		return isCore() || extList.isEnabled(ext1Name) || extList.isEnabled(ext2Name);
+	bool isEnabled(uint32_t enabledVersion, const MVKExtensionList& extList) {
+		return (isCore() && MVK_VULKAN_API_VERSION_CONFORM(enabledVersion) >= apiVersion) ||
+			   extList.isEnabled(ext1Name) || extList.isEnabled(ext2Name);
 	}
 } MVKEntryPoint;
 
@@ -65,6 +67,9 @@
 	/** Returns a pointer to the Vulkan instance. */
 	MVKInstance* getInstance() override { return this; }
 
+	/** Returns the maximum version of Vulkan the application supports. */
+	inline uint32_t getAPIVersion() { return _appInfo.apiVersion; }
+
 	/** Returns a pointer to the layer manager. */
 	inline MVKLayerManager* getLayerManager() { return MVKLayerManager::globalManager(); }
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index 9c9dfb1..49cdc7f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -39,9 +39,9 @@
 PFN_vkVoidFunction MVKInstance::getProcAddr(const char* pName) {
 	MVKEntryPoint* pMVKPA = getEntryPoint(pName);
 
-	bool isSupported = (pMVKPA &&									// Command exists and...
-						(pMVKPA->isDevice ||						// ...is a device command or...
-						 pMVKPA->isEnabled(_enabledExtensions)));	// ...is a core or enabled extension command.
+	bool isSupported = (pMVKPA &&														// Command exists and...
+						(pMVKPA->isDevice ||											// ...is a device command or...
+						 pMVKPA->isEnabled(_appInfo.apiVersion, _enabledExtensions)));	// ...is a core or enabled extension command.
 
 	return isSupported ? pMVKPA->functionPointer : nullptr;
 }
@@ -336,8 +336,8 @@
 
 	initDebugCallbacks(pCreateInfo);	// Do before any creation activities
 
-	_appInfo.apiVersion = MVK_VULKAN_API_VERSION;	// Default
 	mvkSetOrClear(&_appInfo, pCreateInfo->pApplicationInfo);
+	if (_appInfo.apiVersion == 0) { _appInfo.apiVersion = VK_API_VERSION_1_0; }	// Default
 
 	initProcAddrs();		// Init function pointers
 	initConfig();
@@ -403,16 +403,19 @@
 	}
 }
 
-#define ADD_ENTRY_POINT(func, ext1, ext2, isDev)	_entryPoints[""#func] = { (PFN_vkVoidFunction)&func,  ext1,  ext2,  isDev }
+#define ADD_ENTRY_POINT(func, api, ext1, ext2, isDev)	_entryPoints[""#func] = { (PFN_vkVoidFunction)&func, api, ext1,  ext2,  isDev }
 
-#define ADD_INST_ENTRY_POINT(func)					ADD_ENTRY_POINT(func, nullptr, nullptr, false)
-#define ADD_DVC_ENTRY_POINT(func)					ADD_ENTRY_POINT(func, nullptr, nullptr, true)
+#define ADD_INST_ENTRY_POINT(func)						ADD_ENTRY_POINT(func, VK_API_VERSION_1_0, nullptr, nullptr, false)
+#define ADD_DVC_ENTRY_POINT(func)						ADD_ENTRY_POINT(func, VK_API_VERSION_1_0, nullptr, nullptr, true)
 
-#define ADD_INST_EXT_ENTRY_POINT(func, EXT)			ADD_ENTRY_POINT(func, VK_ ##EXT ##_EXTENSION_NAME, nullptr, false)
-#define ADD_DVC_EXT_ENTRY_POINT(func, EXT)			ADD_ENTRY_POINT(func, VK_ ##EXT ##_EXTENSION_NAME, nullptr, true)
+#define ADD_INST_1_1_ENTRY_POINT(func)					ADD_ENTRY_POINT(func, VK_API_VERSION_1_1, nullptr, nullptr, false)
+#define ADD_DVC_1_1_ENTRY_POINT(func)					ADD_ENTRY_POINT(func, VK_API_VERSION_1_1, nullptr, nullptr, true)
 
-#define ADD_INST_EXT2_ENTRY_POINT(func, EXT1, EXT2)	ADD_ENTRY_POINT(func, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, false)
-#define ADD_DVC_EXT2_ENTRY_POINT(func, EXT1, EXT2)	ADD_ENTRY_POINT(func, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, true)
+#define ADD_INST_EXT_ENTRY_POINT(func, EXT)			ADD_ENTRY_POINT(func, 0, VK_ ##EXT ##_EXTENSION_NAME, nullptr, false)
+#define ADD_DVC_EXT_ENTRY_POINT(func, EXT)			ADD_ENTRY_POINT(func, 0, VK_ ##EXT ##_EXTENSION_NAME, nullptr, true)
+
+#define ADD_INST_EXT2_ENTRY_POINT(func, EXT1, EXT2)	ADD_ENTRY_POINT(func, 0, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, false)
+#define ADD_DVC_EXT2_ENTRY_POINT(func, EXT1, EXT2)	ADD_ENTRY_POINT(func, 0, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, true)
 
 // Initializes the function pointer map.
 void MVKInstance::initProcAddrs() {
@@ -432,6 +435,18 @@
 	ADD_INST_ENTRY_POINT(vkEnumerateDeviceLayerProperties);
 	ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceSparseImageFormatProperties);
 
+	ADD_INST_1_1_ENTRY_POINT(vkEnumeratePhysicalDeviceGroups);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceFeatures2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceProperties2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceFormatProperties2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceImageFormatProperties2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceQueueFamilyProperties2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceMemoryProperties2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceSparseImageFormatProperties2);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceExternalFenceProperties);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceExternalBufferProperties);
+	ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceExternalSemaphoreProperties);
+
 	// Device functions:
 	ADD_DVC_ENTRY_POINT(vkGetDeviceProcAddr);
 	ADD_DVC_ENTRY_POINT(vkDestroyDevice);
@@ -555,6 +570,23 @@
 	ADD_DVC_ENTRY_POINT(vkCmdEndRenderPass);
 	ADD_DVC_ENTRY_POINT(vkCmdExecuteCommands);
 
+	ADD_DVC_1_1_ENTRY_POINT(vkGetDeviceQueue2);
+	ADD_DVC_1_1_ENTRY_POINT(vkBindBufferMemory2);
+	ADD_DVC_1_1_ENTRY_POINT(vkBindImageMemory2);
+	ADD_DVC_1_1_ENTRY_POINT(vkGetBufferMemoryRequirements2);
+	ADD_DVC_1_1_ENTRY_POINT(vkGetImageMemoryRequirements2);
+	ADD_DVC_1_1_ENTRY_POINT(vkGetImageSparseMemoryRequirements2);
+	ADD_DVC_1_1_ENTRY_POINT(vkGetDeviceGroupPeerMemoryFeatures);
+	ADD_DVC_1_1_ENTRY_POINT(vkCreateDescriptorUpdateTemplate);
+	ADD_DVC_1_1_ENTRY_POINT(vkDestroyDescriptorUpdateTemplate);
+	ADD_DVC_1_1_ENTRY_POINT(vkUpdateDescriptorSetWithTemplate);
+	ADD_DVC_1_1_ENTRY_POINT(vkGetDescriptorSetLayoutSupport);
+	ADD_DVC_1_1_ENTRY_POINT(vkCreateSamplerYcbcrConversion);
+	ADD_DVC_1_1_ENTRY_POINT(vkDestroySamplerYcbcrConversion);
+	ADD_DVC_1_1_ENTRY_POINT(vkTrimCommandPool);
+	ADD_DVC_1_1_ENTRY_POINT(vkCmdSetDeviceMask);
+	ADD_DVC_1_1_ENTRY_POINT(vkCmdDispatchBase);
+
 	// Instance extension functions:
 	ADD_INST_EXT_ENTRY_POINT(vkEnumeratePhysicalDeviceGroupsKHR, KHR_DEVICE_GROUP_CREATION);
 	ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceExternalFencePropertiesKHR, KHR_EXTERNAL_FENCE_CAPABILITIES);
diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
index 2e1c982..1b93fad 100644
--- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
+++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
@@ -35,8 +35,8 @@
 #endif
 
 /** Macro to determine the Vulkan version supported by MoltenVK. */
-#define MVK_VULKAN_API_VERSION		VK_MAKE_VERSION(VK_VERSION_MAJOR(VK_API_VERSION_1_0),	\
-													VK_VERSION_MINOR(VK_API_VERSION_1_0),	\
+#define MVK_VULKAN_API_VERSION		VK_MAKE_VERSION(VK_VERSION_MAJOR(VK_API_VERSION_1_1),	\
+													VK_VERSION_MINOR(VK_API_VERSION_1_1),	\
 													VK_HEADER_VERSION)
 
 /** 
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index 2751526..b360b06 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -158,9 +158,12 @@
 		MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__);											\
 	}
 
+// Define an extension call as an alias of a core call
+#define MVK_PUBLIC_CORE_ALIAS(vkf)	MVK_PUBLIC_ALIAS(vkf##KHR, vkf)
+
 
 #pragma mark -
-#pragma mark Vulkan calls
+#pragma mark Vulkan 1.0 calls
 
 MVK_PUBLIC_SYMBOL VkResult vkCreateInstance(
     const VkInstanceCreateInfo*                 pCreateInfo,
@@ -278,6 +281,8 @@
 		func = (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties;
 	} else if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) {
 		func = (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties;
+	} else if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) {
+		func = (PFN_vkVoidFunction)vkEnumerateInstanceVersion;
 	} else if (instance) {
 		MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
 		func = mvkInst->getProcAddr(pName);
@@ -1900,12 +1905,156 @@
 
 
 #pragma mark -
-#pragma mark VK_KHR_bind_memory2 extension
+#pragma mark Vulkan 1.1 calls
 
-MVK_PUBLIC_SYMBOL VkResult vkBindBufferMemory2KHR(
+MVK_PUBLIC_SYMBOL VkResult vkEnumerateInstanceVersion(
+    uint32_t*                                   pApiVersion) {
+
+    MVKTraceVulkanCallStart();
+    *pApiVersion = MVK_VULKAN_API_VERSION;
+    MVKTraceVulkanCallEnd();
+    return VK_SUCCESS;
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkEnumeratePhysicalDeviceGroups(
+    VkInstance                                  instance,
+    uint32_t*                                   pPhysicalDeviceGroupCount,
+    VkPhysicalDeviceGroupProperties*            pPhysicalDeviceGroupProperties) {
+    MVKTraceVulkanCallStart();
+    MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
+    VkResult rslt = mvkInst->getPhysicalDeviceGroups(pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+    MVKTraceVulkanCallEnd();
+    return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFeatures2(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceFeatures2*                  pFeatures) {
+    
+	MVKTraceVulkanCallStart();
+    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+    mvkPD->getFeatures(pFeatures);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceProperties2*                pProperties) {
+
+	MVKTraceVulkanCallStart();
+    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+    mvkPD->getProperties(pProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFormatProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkFormatProperties2*                        pFormatProperties) {
+    
+	MVKTraceVulkanCallStart();
+    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+    mvkPD->getFormatProperties(format, pFormatProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkGetPhysicalDeviceImageFormatProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2*     pImageFormatInfo,
+    VkImageFormatProperties2*                   pImageFormatProperties) {
+    
+	MVKTraceVulkanCallStart();
+    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+    VkResult rslt = mvkPD->getImageFormatProperties(pImageFormatInfo, pImageFormatProperties);
+	MVKTraceVulkanCallEnd();
+	return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceQueueFamilyProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2*                   pQueueFamilyProperties) {
+    
+	MVKTraceVulkanCallStart();
+    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+    mvkPD->getQueueFamilyProperties(pQueueFamilyPropertyCount, pQueueFamilyProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceMemoryProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceMemoryProperties2*          pMemoryProperties) {
+
+	MVKTraceVulkanCallStart();
+    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+    mvkPD->getMemoryProperties(pMemoryProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties2(
+    VkPhysicalDevice                              physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+    uint32_t*                                     pPropertyCount,
+    VkSparseImageFormatProperties2*               pProperties) {
+
+	MVKTraceVulkanCallStart();
+
+	// Metal does not support sparse images.
+	// Vulkan spec: "If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given arguments,
+	// pPropertyCount will be set to zero upon return, and no data will be written to pProperties.".
+
+    *pPropertyCount = 0;
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalFenceProperties(
+	VkPhysicalDevice                            physicalDevice,
+	const VkPhysicalDeviceExternalFenceInfo*    pExternalFenceInfo,
+	VkExternalFenceProperties*                  pExternalFenceProperties) {
+
+	MVKTraceVulkanCallStart();
+	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+	mvkPD->getExternalFenceProperties(pExternalFenceInfo, pExternalFenceProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalBufferProperties(
+	VkPhysicalDevice                            physicalDevice,
+	const VkPhysicalDeviceExternalBufferInfo*   pExternalBufferInfo,
+	VkExternalBufferProperties*                 pExternalBufferProperties) {
+
+	MVKTraceVulkanCallStart();
+	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+	mvkPD->getExternalBufferProperties(pExternalBufferInfo, pExternalBufferProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalSemaphoreProperties(
+	VkPhysicalDevice                             physicalDevice,
+	const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+	VkExternalSemaphoreProperties*               pExternalSemaphoreProperties) {
+
+	MVKTraceVulkanCallStart();
+	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+	mvkPD->getExternalSemaphoreProperties(pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetDeviceQueue2(
+    VkDevice                                    device,
+    const VkDeviceQueueInfo2*                   pQueueInfo,
+    VkQueue*                                    pQueue) {
+
+	MVKTraceVulkanCallStart();
+	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+	*pQueue = mvkDev->getQueue(pQueueInfo)->getVkQueue();
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkBindBufferMemory2(
 	VkDevice									device,
 	uint32_t									bindInfoCount,
-	const VkBindBufferMemoryInfoKHR*			pBindInfos) {
+	const VkBindBufferMemoryInfo*				pBindInfos) {
 
 	MVKTraceVulkanCallStart();
 	VkResult rslt = VK_SUCCESS;
@@ -1918,10 +2067,10 @@
 	return rslt;
 }
 
-MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2KHR(
+MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2(
 	VkDevice									device,
 	uint32_t									bindInfoCount,
-	const VkBindImageMemoryInfoKHR*				pBindInfos) {
+	const VkBindImageMemoryInfo*				pBindInfos) {
 
 	MVKTraceVulkanCallStart();
 	VkResult rslt = VK_SUCCESS;
@@ -1934,29 +2083,76 @@
 	return rslt;
 }
 
+MVK_PUBLIC_SYMBOL void vkGetBufferMemoryRequirements2(
+    VkDevice                                    device,
+    const VkBufferMemoryRequirementsInfo2*      pInfo,
+    VkMemoryRequirements2*                      pMemoryRequirements) {
 
-#pragma mark -
-#pragma mark VK_KHR_descriptor_update_template extension
+	MVKTraceVulkanCallStart();
+    MVKBuffer* mvkBuff = (MVKBuffer*)pInfo->buffer;
+    mvkBuff->getMemoryRequirements(pInfo, pMemoryRequirements);
+	MVKTraceVulkanCallEnd();
+}
 
-MVK_PUBLIC_SYMBOL VkResult vkCreateDescriptorUpdateTemplateKHR(
+MVK_PUBLIC_SYMBOL void vkGetImageMemoryRequirements2(
+    VkDevice                                    device,
+    const VkImageMemoryRequirementsInfo2*       pInfo,
+    VkMemoryRequirements2*                      pMemoryRequirements) {
+
+	MVKTraceVulkanCallStart();
+    auto* mvkImg = (MVKImage*)pInfo->image;
+    mvkImg->getMemoryRequirements(pInfo, pMemoryRequirements);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetImageSparseMemoryRequirements2(
+    VkDevice                                        device,
+    const VkImageSparseMemoryRequirementsInfo2*     pInfo,
+    uint32_t*                                       pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements2*               pSparseMemoryRequirements) {
+
+	MVKTraceVulkanCallStart();
+
+	// Metal does not support sparse images.
+	// Vulkan spec: "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then
+	// pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to.".
+
+    *pSparseMemoryRequirementCount = 0;
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetDeviceGroupPeerMemoryFeatures(
+    VkDevice                                    device,
+    uint32_t                                    heapIndex,
+    uint32_t                                    localDeviceIndex,
+    uint32_t                                    remoteDeviceIndex,
+    VkPeerMemoryFeatureFlags*                   pPeerMemoryFeatures) {
+
+    MVKTraceVulkanCallStart();
+    MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+    mvkDev->getPeerMemoryFeatures(heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+    MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkCreateDescriptorUpdateTemplate(
     VkDevice                                       device,
-    const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+    const VkDescriptorUpdateTemplateCreateInfo*    pCreateInfo,
     const VkAllocationCallbacks*                   pAllocator,
-    VkDescriptorUpdateTemplateKHR*                 pDescriptorUpdateTemplate) {
+    VkDescriptorUpdateTemplate*                    pDescriptorUpdateTemplate) {
 
 	MVKTraceVulkanCallStart();
     MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
     auto *mvkDUT = mvkDev->createDescriptorUpdateTemplate(pCreateInfo,
                                                           pAllocator);
-    *pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplateKHR)mvkDUT;
+    *pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplate)mvkDUT;
     VkResult rslt = mvkDUT->getConfigurationResult();
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
 
-MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplateKHR(
+MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplate(
     VkDevice                                    device,
-    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
     const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
@@ -1965,10 +2161,10 @@
 	MVKTraceVulkanCallEnd();
 }
 
-MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplateKHR(
+MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplate(
     VkDevice                                    device,
     VkDescriptorSet                             descriptorSet,
-    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
     const void*                                 pData) {
 
 	MVKTraceVulkanCallStart();
@@ -1976,24 +2172,56 @@
 	MVKTraceVulkanCallEnd();
 }
 
-
-#pragma mark -
-#pragma mark VK_KHR_device_group extension
-
-MVK_PUBLIC_SYMBOL void vkGetDeviceGroupPeerMemoryFeaturesKHR(
+MVK_PUBLIC_SYMBOL void vkGetDescriptorSetLayoutSupport(
     VkDevice                                    device,
-    uint32_t                                    heapIndex,
-    uint32_t                                    localDeviceIndex,
-    uint32_t                                    remoteDeviceIndex,
-    VkPeerMemoryFeatureFlagsKHR*                pPeerMemoryFeatures) {
+    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+    VkDescriptorSetLayoutSupport*               pSupport) {
 
-    MVKTraceVulkanCallStart();
-    MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
-    mvkDev->getPeerMemoryFeatures(heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
-    MVKTraceVulkanCallEnd();
+	MVKTraceVulkanCallStart();
+	MVKDevice* mvkDevice = MVKDevice::getMVKDevice(device);
+    mvkDevice->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
+	MVKTraceVulkanCallEnd();
 }
 
-MVK_PUBLIC_SYMBOL void vkCmdSetDeviceMaskKHR(
+MVK_PUBLIC_SYMBOL VkResult vkCreateSamplerYcbcrConversion(
+    VkDevice                                    device,
+    const VkSamplerYcbcrConversionCreateInfo*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSamplerYcbcrConversion*                   pYcbcrConversion) {
+
+    MVKTraceVulkanCallStart();
+	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+	MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
+	*pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
+	VkResult rslt = mvkSampConv->getConfigurationResult();
+	MVKTraceVulkanCallEnd();
+	return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkDestroySamplerYcbcrConversion(
+    VkDevice                                    device,
+    VkSamplerYcbcrConversion                    ycbcrConversion,
+    const VkAllocationCallbacks*                pAllocator) {
+
+    MVKTraceVulkanCallStart();
+	if ( !ycbcrConversion ) { return; }
+	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+	mvkDev->destroySamplerYcbcrConversion((MVKSamplerYcbcrConversion*)ycbcrConversion, pAllocator);
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkTrimCommandPool(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    VkCommandPoolTrimFlags                      flags) {
+
+	MVKTraceVulkanCallStart();
+	MVKCommandPool* mvkCmdPool = (MVKCommandPool*)commandPool;
+    mvkCmdPool->trim();
+	MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkCmdSetDeviceMask(
     VkCommandBuffer                             commandBuffer,
     uint32_t                                    deviceMask) {
 
@@ -2003,7 +2231,7 @@
     MVKTraceVulkanCallEnd();
 }
 
-MVK_PUBLIC_SYMBOL void vkCmdDispatchBaseKHR(
+MVK_PUBLIC_SYMBOL void vkCmdDispatchBase(
     VkCommandBuffer                             commandBuffer,
     uint32_t                                    baseGroupX,
     uint32_t                                    baseGroupY,
@@ -2019,219 +2247,82 @@
 
 
 #pragma mark -
+#pragma mark VK_KHR_bind_memory2 extension
+
+MVK_PUBLIC_CORE_ALIAS(vkBindBufferMemory2);
+MVK_PUBLIC_CORE_ALIAS(vkBindImageMemory2);
+
+
+#pragma mark -
+#pragma mark VK_KHR_descriptor_update_template extension
+
+MVK_PUBLIC_CORE_ALIAS(vkCreateDescriptorUpdateTemplate);
+MVK_PUBLIC_CORE_ALIAS(vkDestroyDescriptorUpdateTemplate);
+MVK_PUBLIC_CORE_ALIAS(vkUpdateDescriptorSetWithTemplate);
+
+
+#pragma mark -
+#pragma mark VK_KHR_device_group extension
+
+MVK_PUBLIC_CORE_ALIAS(vkGetDeviceGroupPeerMemoryFeatures);
+MVK_PUBLIC_CORE_ALIAS(vkCmdSetDeviceMask);
+MVK_PUBLIC_CORE_ALIAS(vkCmdDispatchBase);
+
+
+#pragma mark -
 #pragma mark VK_KHR_device_group_creation extension
 
-MVK_PUBLIC_SYMBOL VkResult vkEnumeratePhysicalDeviceGroupsKHR(
-    VkInstance                                  instance,
-    uint32_t*                                   pPhysicalDeviceGroupCount,
-    VkPhysicalDeviceGroupPropertiesKHR*         pPhysicalDeviceGroupProperties) {
-    MVKTraceVulkanCallStart();
-    MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
-    VkResult rslt = mvkInst->getPhysicalDeviceGroups(pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-    MVKTraceVulkanCallEnd();
-    return rslt;
-}
+MVK_PUBLIC_CORE_ALIAS(vkEnumeratePhysicalDeviceGroups);
 
 
 #pragma mark -
 #pragma mark VK_KHR_external_fence_capabilities extension
 
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalFencePropertiesKHR(
-	VkPhysicalDevice                            physicalDevice,
-	const VkPhysicalDeviceExternalFenceInfo*    pExternalFenceInfo,
-	VkExternalFenceProperties*                  pExternalFenceProperties) {
-
-	MVKTraceVulkanCallStart();
-	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-	mvkPD->getExternalFenceProperties(pExternalFenceInfo, pExternalFenceProperties);
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalFenceProperties);
 
 
 #pragma mark -
 #pragma mark VK_KHR_external_memory_capabilities extension
 
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalBufferPropertiesKHR(
-	VkPhysicalDevice                            physicalDevice,
-	const VkPhysicalDeviceExternalBufferInfo*   pExternalBufferInfo,
-	VkExternalBufferProperties*                 pExternalBufferProperties) {
-
-	MVKTraceVulkanCallStart();
-	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-	mvkPD->getExternalBufferProperties(pExternalBufferInfo, pExternalBufferProperties);
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalBufferProperties);
 
 
 #pragma mark -
 #pragma mark VK_KHR_external_semaphore_capabilities extension
 
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
-	VkPhysicalDevice                             physicalDevice,
-	const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
-	VkExternalSemaphoreProperties*               pExternalSemaphoreProperties) {
-
-	MVKTraceVulkanCallStart();
-	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-	mvkPD->getExternalSemaphoreProperties(pExternalSemaphoreInfo, pExternalSemaphoreProperties);
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalSemaphoreProperties);
 
 
 #pragma mark -
 #pragma mark VK_KHR_get_memory_requirements2 extension
 
-MVK_PUBLIC_SYMBOL void vkGetBufferMemoryRequirements2KHR(
-    VkDevice                                    device,
-    const VkBufferMemoryRequirementsInfo2KHR*   pInfo,
-    VkMemoryRequirements2KHR*                   pMemoryRequirements) {
-
-	MVKTraceVulkanCallStart();
-    MVKBuffer* mvkBuff = (MVKBuffer*)pInfo->buffer;
-    mvkBuff->getMemoryRequirements(pInfo, pMemoryRequirements);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetImageMemoryRequirements2KHR(
-    VkDevice                                    device,
-    const VkImageMemoryRequirementsInfo2KHR*    pInfo,
-    VkMemoryRequirements2KHR*                   pMemoryRequirements) {
-
-	MVKTraceVulkanCallStart();
-    auto* mvkImg = (MVKImage*)pInfo->image;
-    mvkImg->getMemoryRequirements(pInfo, pMemoryRequirements);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetImageSparseMemoryRequirements2KHR(
-    VkDevice                                        device,
-    const VkImageSparseMemoryRequirementsInfo2KHR*  pInfo,
-    uint32_t*                                       pSparseMemoryRequirementCount,
-    VkSparseImageMemoryRequirements2KHR*            pSparseMemoryRequirements) {
-
-	MVKTraceVulkanCallStart();
-
-	// Metal does not support sparse images.
-	// Vulkan spec: "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then
-	// pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to.".
-
-    *pSparseMemoryRequirementCount = 0;
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetBufferMemoryRequirements2);
+MVK_PUBLIC_CORE_ALIAS(vkGetImageMemoryRequirements2);
+MVK_PUBLIC_CORE_ALIAS(vkGetImageSparseMemoryRequirements2);
 
 
 #pragma mark -
 #pragma mark VK_KHR_get_physical_device_properties2 extension
 
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFeatures2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceFeatures2KHR*               pFeatures) {
-    
-	MVKTraceVulkanCallStart();
-    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    mvkPD->getFeatures(pFeatures);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceProperties2KHR*             pProperties) {
-
-	MVKTraceVulkanCallStart();
-    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    mvkPD->getProperties(pProperties);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFormatProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkFormat                                    format,
-    VkFormatProperties2KHR*                     pFormatProperties) {
-    
-	MVKTraceVulkanCallStart();
-    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    mvkPD->getFormatProperties(format, pFormatProperties);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL VkResult vkGetPhysicalDeviceImageFormatProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceImageFormatInfo2KHR*  pImageFormatInfo,
-    VkImageFormatProperties2KHR*                pImageFormatProperties) {
-    
-	MVKTraceVulkanCallStart();
-    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    VkResult rslt = mvkPD->getImageFormatProperties(pImageFormatInfo, pImageFormatProperties);
-	MVKTraceVulkanCallEnd();
-	return rslt;
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceQueueFamilyProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t*                                   pQueueFamilyPropertyCount,
-    VkQueueFamilyProperties2KHR*                pQueueFamilyProperties) {
-    
-	MVKTraceVulkanCallStart();
-    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    mvkPD->getQueueFamilyProperties(pQueueFamilyPropertyCount, pQueueFamilyProperties);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceMemoryProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceMemoryProperties2KHR*       pMemoryProperties) {
-
-	MVKTraceVulkanCallStart();
-    MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    mvkPD->getMemoryProperties(pMemoryProperties);
-	MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
-    uint32_t*                                   pPropertyCount,
-    VkSparseImageFormatProperties2KHR*          pProperties) {
-
-	MVKTraceVulkanCallStart();
-
-	// Metal does not support sparse images.
-	// Vulkan spec: "If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given arguments,
-	// pPropertyCount will be set to zero upon return, and no data will be written to pProperties.".
-
-    *pPropertyCount = 0;
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceFeatures2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceFormatProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceImageFormatProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceQueueFamilyProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceMemoryProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceSparseImageFormatProperties2);
 
 
 #pragma mark -
 #pragma mark VK_KHR_maintenance1 extension
 
-MVK_PUBLIC_SYMBOL void vkTrimCommandPoolKHR(
-    VkDevice                                    device,
-    VkCommandPool                               commandPool,
-    VkCommandPoolTrimFlagsKHR                   flags) {
-
-	MVKTraceVulkanCallStart();
-	MVKCommandPool* mvkCmdPool = (MVKCommandPool*)commandPool;
-    mvkCmdPool->trim();
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkTrimCommandPool);
 
 
 #pragma mark -
 #pragma mark VK_KHR_maintenance3 extension
 
-MVK_PUBLIC_SYMBOL void vkGetDescriptorSetLayoutSupportKHR(
-    VkDevice                                    device,
-    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
-    VkDescriptorSetLayoutSupportKHR*            pSupport) {
-
-	MVKTraceVulkanCallStart();
-	MVKDevice* mvkDevice = MVKDevice::getMVKDevice(device);
-    mvkDevice->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetDescriptorSetLayoutSupport);
 
 
 #pragma mark -
@@ -2266,32 +2357,8 @@
 #pragma mark -
 #pragma mark VK_KHR_sampler_ycbcr_conversion extension
 
-MVK_PUBLIC_SYMBOL VkResult vkCreateSamplerYcbcrConversionKHR(
-    VkDevice                                    device,
-    const VkSamplerYcbcrConversionCreateInfo*   pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSamplerYcbcrConversion*                   pYcbcrConversion) {
-
-    MVKTraceVulkanCallStart();
-	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
-	MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
-	*pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
-	VkResult rslt = mvkSampConv->getConfigurationResult();
-	MVKTraceVulkanCallEnd();
-	return rslt;
-}
-
-MVK_PUBLIC_SYMBOL void vkDestroySamplerYcbcrConversionKHR(
-    VkDevice                                    device,
-    VkSamplerYcbcrConversion                    ycbcrConversion,
-    const VkAllocationCallbacks*                pAllocator) {
-
-    MVKTraceVulkanCallStart();
-	if ( !ycbcrConversion ) { return; }
-	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
-	mvkDev->destroySamplerYcbcrConversion((MVKSamplerYcbcrConversion*)ycbcrConversion, pAllocator);
-	MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkCreateSamplerYcbcrConversion);
+MVK_PUBLIC_CORE_ALIAS(vkDestroySamplerYcbcrConversion);
 
 
 #pragma mark -