Merge pull request #1636 from spnda/fix_swapchain_color_space

Fix: No need to check if EXT_swapchain_color_space was enabled
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index b7f572d..b82aa34 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -263,6 +263,7 @@
 - `VK_KHR_16bit_storage`
 - `VK_KHR_8bit_storage`
 - `VK_KHR_bind_memory2`
+- `VK_KHR_buffer_device_address` *(requires Metal 3.0)*
 - `VK_KHR_create_renderpass2`
 - `VK_KHR_dedicated_allocation`
 - `VK_KHR_depth_stencil_resolve`
@@ -297,6 +298,7 @@
 - `VK_KHR_timeline_semaphore`
 - `VK_KHR_uniform_buffer_standard_layout`
 - `VK_KHR_variable_pointers`
+- `VK_EXT_buffer_device_address` *(requires Metal 3.0)*
 - `VK_EXT_debug_marker`
 - `VK_EXT_debug_report`
 - `VK_EXT_debug_utils`
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index e3b9683..5c1622f 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -20,9 +20,15 @@
 
 - Add support for extensions:
 	- `VK_EXT_metal_objects`
+	- `VK_KHR_buffer_device_address` and `VK_EXT_buffer_device_address`.
 - Reducing redundant state changes to improve command encoding performance.
 - Update minimum Xcode deployment targets to macOS 10.13, iOS 11, and tvOS 11,
   to avoid Xcode build warnings in Xcode 14.
+- Work around MTLCounterSet crash on additional Intel Iris Plus Graphics drivers.
+- Check `MTLDevice` to enable support for `VK_KHR_fragment_shader_barycentric` 
+  and `VK_NV_fragment_shader_barycentric` extensions.
+- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to version `35`.
+
 
 
 MoltenVK 1.1.10
@@ -35,7 +41,7 @@
 	  updated to indicate the impact of the `VK_KHR_portability_enumeration` extension during 
 	  runtime loading on *macOS* via the *Vulkan Loader*.
 	- `VK_KHR_dynamic_rendering`
-	- `VK_KHR_fragment_shader_barycentric`
+	- `VK_KHR_fragment_shader_barycentric` and `VK_NV_fragment_shader_barycentric`
 	- `VK_KHR_separate_depth_stencil_layouts`
 	- `VK_EXT_separate_stencil_usage`
 - Implement `vkGetRefreshCycleDurationGOOGLE()` for _macOS_.
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index 6a4e776..33777a7 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-50b4d5389b6a06f86fb63a2848e1a7da6d9755ca
+d8d051381f65b9606fb8016c79b7c3bab872eec3
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index 4a99c3d..0d6c35a 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -55,7 +55,7 @@
 #define MVK_MAKE_VERSION(major, minor, patch)    (((major) * 10000) + ((minor) * 100) + (patch))
 #define MVK_VERSION     MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
 
-#define VK_MVK_MOLTENVK_SPEC_VERSION            34
+#define VK_MVK_MOLTENVK_SPEC_VERSION            35
 #define VK_MVK_MOLTENVK_EXTENSION_NAME          "VK_MVK_moltenvk"
 
 /** Identifies the level of logging MoltenVK should be limited to outputting. */
@@ -930,6 +930,7 @@
 	MVKFloatRounding clearColorFloatRounding;		/**< Identifies the type of rounding Metal uses for MTLClearColor float to integer conversions. */
 	MVKCounterSamplingFlags counterSamplingPoints;	/**< Identifies the points where pipeline GPU counter sampling may occur. */
 	VkBool32 programmableSamplePositions;			/**< If true, programmable MSAA sample positions are supported. */
+	VkBool32 shaderBarycentricCoordinates;			/**< If true, fragment shader barycentric coordinates are supported. */
 } MVKPhysicalDeviceMetalFeatures;
 
 /** MoltenVK performance of a particular type of activity. */
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 00d32a4..c6ce85c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -274,7 +274,7 @@
 	/** Destroys all currently allocated descriptor sets. */
 	VkResult reset(VkDescriptorPoolResetFlags flags);
 
-	MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo, bool poolDescriptors);
+	MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo);
 
 	~MVKDescriptorPool() override;
 
@@ -291,7 +291,9 @@
 	void initMetalArgumentBuffer(const VkDescriptorPoolCreateInfo* pCreateInfo);
 	NSUInteger getMetalArgumentBufferResourceStorageSize(NSUInteger bufferCount, NSUInteger textureCount, NSUInteger samplerCount);
 	MTLArgumentDescriptor* getMTLArgumentDescriptor(MTLDataType resourceType, NSUInteger argIndex, NSUInteger count);
+	size_t getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorType descriptorType);
 
+    bool _hasPooledDescriptors;
 	MVKSmallVector<MVKDescriptorSet> _descriptorSets;
 	MVKBitArray _descriptorSetAvailablility;
 	id<MTLBuffer> _metalArgumentBuffer;
@@ -310,7 +312,6 @@
 	MVKDescriptorTypePool<MVKCombinedImageSamplerDescriptor> _combinedImageSamplerDescriptors;
 	MVKDescriptorTypePool<MVKUniformTexelBufferDescriptor> _uniformTexelBufferDescriptors;
 	MVKDescriptorTypePool<MVKStorageTexelBufferDescriptor> _storageTexelBufferDescriptors;
-	bool _hasPooledDescriptors;
 };
 
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index e62e526..86a6efd 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -671,26 +671,15 @@
 // or zero if we are not preallocating descriptors in the pool.
 // There may be more than one poolSizeCount instance for the desired VkDescriptorType.
 // Accumulate the descriptor count for the desired VkDescriptorType accordingly.
-static size_t getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorType descriptorType, bool poolDescriptors) {
-	uint32_t descCnt = 0;
-	if (poolDescriptors) {
-		uint32_t poolCnt = pCreateInfo->poolSizeCount;
-		for (uint32_t poolIdx = 0; poolIdx < poolCnt; poolIdx++) {
-			auto& poolSize = pCreateInfo->pPoolSizes[poolIdx];
-			if (poolSize.type == descriptorType) { descCnt += poolSize.descriptorCount; }
-		}
-	}
-	return descCnt;
-}
+// For descriptors of the VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT type,
+// we accumulate the count via the pNext chain.
+size_t MVKDescriptorPool::getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo,
+									  VkDescriptorType descriptorType) {
 
-// Return the size of the preallocated pool for descriptors of the
-// VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT type, or zero if we
-// are not preallocating descriptors in the pool.
-// For consistency with getPoolSize() behavior, we support more than one pNext entry
-// for inline blocks. Accumulate the descriptor count for inline blocks accordingly.
-static size_t getInlineBlockPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, bool poolDescriptors) {
+	if ( !_hasPooledDescriptors ) { return 0; }
+
 	uint32_t descCnt = 0;
-	if (poolDescriptors) {
+	if (descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
 		for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
 			switch (next->sType) {
 				case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT: {
@@ -702,30 +691,33 @@
 					break;
 			}
 		}
+	} else {
+		for (uint32_t poolIdx = 0; poolIdx < pCreateInfo->poolSizeCount; poolIdx++) {
+			auto& poolSize = pCreateInfo->pPoolSizes[poolIdx];
+			if (poolSize.type == descriptorType) { descCnt += poolSize.descriptorCount; }
+		}
 	}
 	return descCnt;
 }
 
-// Although poolDescriptors is derived from MVKConfiguration, it is passed in here to ensure all components of this instance see a SVOT for this value.
-// Alternate might have been to force _hasPooledDescriptors to be set first by changing member declaration order in class declaration.
-MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo, bool poolDescriptors) :
+MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo) :
 	MVKVulkanAPIDeviceObject(device),
+    _hasPooledDescriptors(mvkConfig().preallocateDescriptors),		// Set this first! Accessed by MVKDescriptorSet constructor and getPoolSize() in following lines.
 	_descriptorSets(pCreateInfo->maxSets, MVKDescriptorSet(this)),
 	_descriptorSetAvailablility(pCreateInfo->maxSets, true),
 	_inlineBlockMTLBufferAllocator(device, device->_pMetalFeatures->dynamicMTLBufferSize, true),
-	_uniformBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, poolDescriptors)),
-	_storageBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, poolDescriptors)),
-	_uniformBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, poolDescriptors)),
-	_storageBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, poolDescriptors)),
-	_inlineUniformBlockDescriptors(getInlineBlockPoolSize(pCreateInfo, poolDescriptors)),
-	_sampledImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, poolDescriptors)),
-	_storageImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, poolDescriptors)),
-	_inputAttachmentDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, poolDescriptors)),
-	_samplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLER, poolDescriptors)),
-	_combinedImageSamplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, poolDescriptors)),
-	_uniformTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, poolDescriptors)),
-	_storageTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, poolDescriptors)),
-	_hasPooledDescriptors(poolDescriptors) {
+	_uniformBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)),
+	_storageBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)),
+	_uniformBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)),
+	_storageBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)),
+	_inlineUniformBlockDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)),
+	_sampledImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)),
+	_storageImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)),
+	_inputAttachmentDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)),
+	_samplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLER)),
+	_combinedImageSamplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)),
+	_uniformTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)),
+    _storageTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)) {
 		initMetalArgumentBuffer(pCreateInfo);
 	}
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index 9989a69..f7bc5ac 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -393,6 +393,7 @@
 	void initExternalMemoryProperties();
 	void initExtensions();
 	void initCounterSets();
+	bool needsCounterSetRetained();
 	MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
 	void initPipelineCacheUUID();
 	uint32_t getHighestGPUCapability();
@@ -794,6 +795,9 @@
 	const VkPhysicalDeviceImagelessFramebufferFeaturesKHR _enabledImagelessFramebufferFeatures;
 	const VkPhysicalDeviceDynamicRenderingFeatures _enabledDynamicRenderingFeatures;
 	const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures _enabledSeparateDepthStencilLayoutsFeatures;
+	const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR _enabledFragmentShaderBarycentricFeatures;
+	const VkPhysicalDeviceBufferDeviceAddressFeatures _enabledBufferDeviceAddressFeatures;
+	const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT _enabledBufferDeviceAddressFeaturesEXT;
 
 	/** Pointer to the Metal-specific features of the underlying physical device. */
 	const MVKPhysicalDeviceMetalFeatures* _pMetalFeatures;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index e12e8cb..4316cc6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -288,16 +288,23 @@
 				break;
 			}
             case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: {
-                auto* barycentricProperties = (VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR*)next;
-                barycentricProperties->fragmentShaderBarycentric = true;
+                auto* barycentricFeatures = (VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR*)next;
+				barycentricFeatures->fragmentShaderBarycentric = true;
                 break;
             }
             case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: {
                 auto* bufferDeviceAddressFeatures = (VkPhysicalDeviceBufferDeviceAddressFeatures*)next;
-                bufferDeviceAddressFeatures->bufferDeviceAddress = true;
+                bufferDeviceAddressFeatures->bufferDeviceAddress = mvkOSVersionIsAtLeast(12.05, 16.0);
                 bufferDeviceAddressFeatures->bufferDeviceAddressCaptureReplay = false;
                 bufferDeviceAddressFeatures->bufferDeviceAddressMultiDevice = false;
             }
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: {
+				auto* bufferDeviceAddressFeatures = (VkPhysicalDeviceBufferDeviceAddressFeaturesEXT*)next;
+				bufferDeviceAddressFeatures->bufferDeviceAddress = mvkOSVersionIsAtLeast(12.05, 16.0);
+				bufferDeviceAddressFeatures->bufferDeviceAddressCaptureReplay = false;
+				bufferDeviceAddressFeatures->bufferDeviceAddressMultiDevice = false;
+				break;
+			}
 			default:
 				break;
 		}
@@ -1600,6 +1607,13 @@
 		_metalFeatures.pullModelInterpolation = _mtlDevice.supportsPullModelInterpolation;
 	}
 #endif
+
+#if (MVK_MACOS && !MVK_MACCAT) || (MVK_MACCAT && MVK_XCODE_14) || (MVK_IOS && MVK_XCODE_12)
+	if ( [_mtlDevice respondsToSelector: @selector(supportsShaderBarycentricCoordinates)] ) {
+		_metalFeatures.shaderBarycentricCoordinates = _mtlDevice.supportsShaderBarycentricCoordinates;
+	}
+#endif
+
     if ( [_mtlDevice respondsToSelector: @selector(maxBufferLength)] ) {
         _metalFeatures.maxMTLBufferSize = _mtlDevice.maxBufferLength;
     }
@@ -1686,7 +1700,7 @@
 		case MTLLanguageVersion1_1:
 			setMSLVersion(1, 1);
 			break;
-#if MVK_IOS_OR_TVOS || MVK_XCODE_14
+#if MVK_IOS_OR_TVOS
 		case MTLLanguageVersion1_0:
 			setMSLVersion(1, 0);
 			break;
@@ -2833,6 +2847,10 @@
 	if (!_metalFeatures.simdPermute && !_metalFeatures.quadPermute) {
 		pWritableExtns->vk_KHR_shader_subgroup_extended_types.enabled = false;
 	}
+	if (!_metalFeatures.shaderBarycentricCoordinates) {
+		pWritableExtns->vk_KHR_fragment_shader_barycentric.enabled = false;
+		pWritableExtns->vk_NV_fragment_shader_barycentric.enabled = false;
+	}
 #if MVK_MACOS
 	if (!supportsMTLGPUFamily(Apple5)) {
 		pWritableExtns->vk_AMD_shader_image_load_store_lod.enabled = false;
@@ -2847,12 +2865,7 @@
 		if (_metalFeatures.counterSamplingPoints) {
 			NSArray<id<MTLCounterSet>>* counterSets = _mtlDevice.counterSets;
 
-			// Workaround for a bug in Intel Iris Plus Graphics driver where the counterSets
-			// array is not properly retained internally, and becomes a zombie when counterSets
-			// is called more than once, which occurs when an app creates more than one VkInstance.
-			// This workaround will cause a very small memory leak on systems that do not have this
-			// bug, so we apply the workaround only when absolutely needed for specific devices.
-			if (_properties.vendorID == kIntelVendorId && _properties.deviceID == 0x8a53) { [counterSets retain]; }
+			if (needsCounterSetRetained()) { [counterSets retain]; }
 
 			for (id<MTLCounterSet> cs in counterSets){
 				NSString* csName = cs.name;
@@ -2871,6 +2884,27 @@
 	}
 }
 
+// Workaround for a bug in Intel Iris Plus Graphics driver where the counterSets array is
+// not properly retained internally, and becomes a zombie when counterSets is called more
+// than once, which occurs when an app creates more than one VkInstance. This workaround
+// will cause a very small memory leak on systems that do not have this bug, so we apply
+// the workaround only when absolutely needed for specific devices. The list of deviceIDs
+// is sourced from the list of Intel Iris Plus Graphics Gen11 tier G7 devices found here:
+// https://en.wikipedia.org/wiki/List_of_Intel_graphics_processing_units#Gen11
+bool MVKPhysicalDevice::needsCounterSetRetained() {
+
+	if (_properties.vendorID != kIntelVendorId) { return false; }
+
+	switch (_properties.deviceID) {
+		case 0x8a51:
+		case 0x8a52:
+		case 0x8a53:
+			return true;
+		default:
+			return false;
+	}
+}
+
 void MVKPhysicalDevice::logGPUInfo() {
 	string devTypeStr;
 	switch (_properties.deviceType) {
@@ -3375,9 +3409,7 @@
 		}
 	}
 
-	if ((pTypeCreateInfo && pTypeCreateInfo->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) ||
-		(pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT) ||
-		 pImportInfo) {
+	if (pTypeCreateInfo && pTypeCreateInfo->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) {
 		if (_pMetalFeatures->events) {
 			return new MVKTimelineSemaphoreMTLEvent(this, pCreateInfo, pTypeCreateInfo, pExportInfo, pImportInfo);
 		} else {
@@ -3385,9 +3417,9 @@
 		}
 	} else {
 		switch (_vkSemaphoreStyle) {
-			case MVKSemaphoreStyleUseMTLEvent:  return new MVKSemaphoreMTLEvent(this, pCreateInfo);
-			case MVKSemaphoreStyleUseMTLFence:  return new MVKSemaphoreMTLFence(this, pCreateInfo);
-			case MVKSemaphoreStyleUseEmulation: return new MVKSemaphoreEmulated(this, pCreateInfo);
+			case MVKSemaphoreStyleUseMTLEvent:  return new MVKSemaphoreMTLEvent(this, pCreateInfo, pExportInfo, pImportInfo);
+			case MVKSemaphoreStyleUseMTLFence:  return new MVKSemaphoreMTLFence(this, pCreateInfo, pExportInfo, pImportInfo);
+			case MVKSemaphoreStyleUseEmulation: return new MVKSemaphoreEmulated(this, pCreateInfo, pExportInfo, pImportInfo);
 		}
 	}
 }
@@ -3567,7 +3599,7 @@
 
 MVKDescriptorPool* MVKDevice::createDescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo,
 												   const VkAllocationCallbacks* pAllocator) {
-	return new MVKDescriptorPool(this, pCreateInfo, mvkConfig().preallocateDescriptors);
+	return new MVKDescriptorPool(this, pCreateInfo);
 }
 
 void MVKDevice::destroyDescriptorPool(MVKDescriptorPool* mvkDP,
@@ -4113,7 +4145,10 @@
 	_enabledPortabilityFeatures(),
 	_enabledImagelessFramebufferFeatures(),
 	_enabledDynamicRenderingFeatures(),
-	_enabledSeparateDepthStencilLayoutsFeatures() {
+	_enabledSeparateDepthStencilLayoutsFeatures(),
+	_enabledFragmentShaderBarycentricFeatures(),
+	_enabledBufferDeviceAddressFeatures(),
+	_enabledBufferDeviceAddressFeaturesEXT() {
 
 		// If the physical device is lost, bail.
 	if (physicalDevice->getConfigurationResult() != VK_SUCCESS) {
@@ -4242,10 +4277,25 @@
 	mvkClear(&_enabledImagelessFramebufferFeatures);
 	mvkClear(&_enabledDynamicRenderingFeatures);
 	mvkClear(&_enabledSeparateDepthStencilLayoutsFeatures);
+	mvkClear(&_enabledFragmentShaderBarycentricFeatures);
+	mvkClear(&_enabledBufferDeviceAddressFeatures);
+	mvkClear(&_enabledBufferDeviceAddressFeaturesEXT);
+
+	VkPhysicalDeviceBufferDeviceAddressFeaturesEXT pdBufferDeviceAddressFeaturesEXT;
+	pdBufferDeviceAddressFeaturesEXT.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT;
+	pdBufferDeviceAddressFeaturesEXT.pNext = nullptr;
+
+	VkPhysicalDeviceBufferDeviceAddressFeatures pdBufferDeviceAddressFeatures;
+	pdBufferDeviceAddressFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
+	pdBufferDeviceAddressFeatures.pNext = &pdBufferDeviceAddressFeaturesEXT;
+
+	VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR pdFragmentShaderBarycentricFeatures;
+	pdFragmentShaderBarycentricFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR;
+	pdFragmentShaderBarycentricFeatures.pNext = &pdBufferDeviceAddressFeatures;
 
 	VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures pdSeparateDepthStencilLayoutsFeatures;
 	pdSeparateDepthStencilLayoutsFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES;
-	pdSeparateDepthStencilLayoutsFeatures.pNext = nullptr;
+	pdSeparateDepthStencilLayoutsFeatures.pNext = &pdFragmentShaderBarycentricFeatures;
 
 	VkPhysicalDeviceDynamicRenderingFeatures pdDynamicRenderingFeatures;
 	pdDynamicRenderingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
@@ -4464,6 +4514,27 @@
 							   &pdSeparateDepthStencilLayoutsFeatures.separateDepthStencilLayouts, 1);
 				break;
 			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: {
+				auto* requestedFeatures = (VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR*)next;
+				enableFeatures(&_enabledFragmentShaderBarycentricFeatures.fragmentShaderBarycentric,
+							   &requestedFeatures->fragmentShaderBarycentric,
+							   &pdFragmentShaderBarycentricFeatures.fragmentShaderBarycentric, 1);
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: {
+				auto* requestedFeatures = (VkPhysicalDeviceBufferDeviceAddressFeatures*)next;
+				enableFeatures(&_enabledBufferDeviceAddressFeatures.bufferDeviceAddress,
+							   &requestedFeatures->bufferDeviceAddress,
+							   &pdBufferDeviceAddressFeatures.bufferDeviceAddress, 3);
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: {
+				auto* requestedFeatures = (VkPhysicalDeviceBufferDeviceAddressFeaturesEXT*)next;
+				enableFeatures(&_enabledBufferDeviceAddressFeaturesEXT.bufferDeviceAddress,
+							   &requestedFeatures->bufferDeviceAddress,
+							   &pdBufferDeviceAddressFeaturesEXT.bufferDeviceAddress, 3);
+				break;
+			}
 			default:
 				break;
 		}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
index 6906ea4..0966dd3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
@@ -165,7 +165,8 @@
 	id<MTLHeap> _mtlHeap = nil;
 	void* _pMemory = nullptr;
 	void* _pHostMemory = nullptr;
-	VkMemoryPropertyFlags _vkMemProps;
+	VkMemoryPropertyFlags _vkMemPropFlags;
+	VkMemoryAllocateFlags _vkMemAllocFlags;
 	MTLStorageMode _mtlStorageMode;
 	MTLCPUCacheMode _mtlCPUCacheMode;
 	bool _isDedicated = false;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
index a397e3c..154eb60 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
@@ -57,7 +57,7 @@
 
 	// Coherent memory does not require flushing by app, so we must flush now
 	// to support Metal textures that actually reside in non-coherent memory.
-	if (mvkIsAnyFlagEnabled(_vkMemProps, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
+	if (mvkIsAnyFlagEnabled(_vkMemPropFlags, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
 		pullFromDevice(offset, size);
 	}
 
@@ -73,7 +73,7 @@
 
 	// Coherent memory does not require flushing by app, so we must flush now
 	// to support Metal textures that actually reside in non-coherent memory.
-	if (mvkIsAnyFlagEnabled(_vkMemProps, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
+	if (mvkIsAnyFlagEnabled(_vkMemPropFlags, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
 		flushToDevice(_mappedRange.offset, _mappedRange.size);
 	}
 
@@ -277,9 +277,9 @@
 								 const VkMemoryAllocateInfo* pAllocateInfo,
 								 const VkAllocationCallbacks* pAllocator) : MVKVulkanAPIDeviceObject(device) {
 	// Set Metal memory parameters
-	_vkMemProps = _device->_pMemoryProperties->memoryTypes[pAllocateInfo->memoryTypeIndex].propertyFlags;
-	_mtlStorageMode = mvkMTLStorageModeFromVkMemoryPropertyFlags(_vkMemProps);
-	_mtlCPUCacheMode = mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(_vkMemProps);
+	_vkMemPropFlags = _device->_pMemoryProperties->memoryTypes[pAllocateInfo->memoryTypeIndex].propertyFlags;
+	_mtlStorageMode = mvkMTLStorageModeFromVkMemoryPropertyFlags(_vkMemPropFlags);
+	_mtlCPUCacheMode = mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(_vkMemPropFlags);
 
 	_allocationSize = pAllocateInfo->allocationSize;
 
@@ -315,6 +315,10 @@
 			case VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT: {
 				const auto* pExportInfo = (VkExportMetalObjectCreateInfoEXT*)next;
 				willExportMTLBuffer = pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT;
+			}
+			case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO: {
+				auto* pMemAllocFlagsInfo = (VkMemoryAllocateFlagsInfo*)next;
+				_vkMemAllocFlags = pMemAllocFlagsInfo->flags;
 				break;
 			}
 			default:
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index 4718594..54a3989 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -649,6 +649,7 @@
 	ADD_DVC_EXT_ENTRY_POINT(vkGetSemaphoreCounterValueKHR, KHR_TIMELINE_SEMAPHORE);
 	ADD_DVC_EXT_ENTRY_POINT(vkSignalSemaphoreKHR, KHR_TIMELINE_SEMAPHORE);
 	ADD_DVC_EXT_ENTRY_POINT(vkWaitSemaphoresKHR, KHR_TIMELINE_SEMAPHORE);
+	ADD_DVC_EXT_ENTRY_POINT(vkGetBufferDeviceAddressEXT, EXT_BUFFER_DEVICE_ADDRESS);
 	ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectTagEXT, EXT_DEBUG_MARKER);
 	ADD_DVC_EXT_ENTRY_POINT(vkDebugMarkerSetObjectNameEXT, EXT_DEBUG_MARKER);
 	ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 6abce41..dc056f0 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -1834,7 +1834,10 @@
 	if (mtlFunc) {
 		MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new];	// temp retain
 		plDesc.computeFunction = mtlFunc;
-		plDesc.maxTotalThreadsPerThreadgroup = _mtlThreadgroupSize.width * _mtlThreadgroupSize.height * _mtlThreadgroupSize.depth;
+		// Only available macOS 10.14+
+		if ([plDesc respondsToSelector:@selector(setMaxTotalThreadsPerThreadgroup:)]) {
+			plDesc.maxTotalThreadsPerThreadgroup = _mtlThreadgroupSize.width * _mtlThreadgroupSize.height * _mtlThreadgroupSize.depth;
+		}
 		plDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = mvkIsAnyFlagEnabled(pCreateInfo->stage.flags, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
 
 		// Metal does not allow the name of the pipeline to be changed after it has been created,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h
index fdbaf4a..3562369 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h
@@ -213,7 +213,10 @@
 	void encodeDeferredSignal(id<MTLCommandBuffer> mtlCmdBuff, uint64_t) override;
 	bool isUsingCommandEncoding() override { return true; }
 
-	MVKSemaphoreMTLFence(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo);
+	MVKSemaphoreMTLFence(MVKDevice* device,
+						 const VkSemaphoreCreateInfo* pCreateInfo,
+						 const VkExportMetalObjectCreateInfoEXT* pExportInfo,
+						 const VkImportMetalSharedEventInfoEXT* pImportInfo);
 
 	~MVKSemaphoreMTLFence() override;
 
@@ -235,7 +238,10 @@
 	void encodeDeferredSignal(id<MTLCommandBuffer> mtlCmdBuff, uint64_t deferToken) override;
 	bool isUsingCommandEncoding() override { return true; }
 
-	MVKSemaphoreMTLEvent(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo);
+	MVKSemaphoreMTLEvent(MVKDevice* device,
+						 const VkSemaphoreCreateInfo* pCreateInfo,
+						 const VkExportMetalObjectCreateInfoEXT* pExportInfo,
+						 const VkImportMetalSharedEventInfoEXT* pImportInfo);
 
 	~MVKSemaphoreMTLEvent() override;
 
@@ -258,7 +264,10 @@
 	void encodeDeferredSignal(id<MTLCommandBuffer> mtlCmdBuff, uint64_t) override;
 	bool isUsingCommandEncoding() override { return false; }
 
-	MVKSemaphoreEmulated(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo);
+	MVKSemaphoreEmulated(MVKDevice* device,
+						 const VkSemaphoreCreateInfo* pCreateInfo,
+						 const VkExportMetalObjectCreateInfoEXT* pExportInfo,
+						 const VkImportMetalSharedEventInfoEXT* pImportInfo);
 
 protected:
 	MVKSemaphoreImpl _blocker;
@@ -296,12 +305,7 @@
 
 #pragma mark Construction
 
-	MVKTimelineSemaphore(MVKDevice* device,
-						 const VkSemaphoreCreateInfo* pCreateInfo,
-						 const VkSemaphoreTypeCreateInfo* pTypeCreateInfo,
-						 const VkExportMetalObjectCreateInfoEXT* pExportInfo,
-						 const VkImportMetalSharedEventInfoEXT* pImportInfo)
-        : MVKSemaphore(device, pCreateInfo) {}
+	MVKTimelineSemaphore(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo) : MVKSemaphore(device, pCreateInfo) {}
 
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
index 60af66b..29d36d3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
@@ -103,9 +103,17 @@
 	encodeSignal(mtlCmdBuff, 0);
 }
 
-MVKSemaphoreMTLFence::MVKSemaphoreMTLFence(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo) :
-	MVKSemaphore(device, pCreateInfo),
-	_mtlFence([device->getMTLDevice() newFence]) {}		//retained
+MVKSemaphoreMTLFence::MVKSemaphoreMTLFence(MVKDevice* device,
+										   const VkSemaphoreCreateInfo* pCreateInfo,
+										   const VkExportMetalObjectCreateInfoEXT* pExportInfo,
+										   const VkImportMetalSharedEventInfoEXT* pImportInfo) : MVKSemaphore(device, pCreateInfo) {
+
+	_mtlFence = [device->getMTLDevice() newFence];		//retained
+
+	if ((pImportInfo && pImportInfo->mtlSharedEvent) || (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT)) {
+		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkCreateEvent(): MTLSharedEvent is not available with VkSemaphores that use MTLFence."));
+	}
+}
 
 MVKSemaphoreMTLFence::~MVKSemaphoreMTLFence() {
 	[_mtlFence release];
@@ -131,10 +139,23 @@
 	if (mtlCmdBuff) { [mtlCmdBuff encodeSignalEvent: _mtlEvent value: deferToken]; }
 }
 
-MVKSemaphoreMTLEvent::MVKSemaphoreMTLEvent(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo) :
-	MVKSemaphore(device, pCreateInfo),
-	_mtlEvent([device->getMTLDevice() newEvent]),	//retained
-	_mtlEventValue(1) {}
+MVKSemaphoreMTLEvent::MVKSemaphoreMTLEvent(MVKDevice* device,
+										   const VkSemaphoreCreateInfo* pCreateInfo,
+										   const VkExportMetalObjectCreateInfoEXT* pExportInfo,
+										   const VkImportMetalSharedEventInfoEXT* pImportInfo) : MVKSemaphore(device, pCreateInfo) {
+	// In order of preference, import a MTLSharedEvent,
+	// create a MTLSharedEvent, or create a MTLEvent.
+	if (pImportInfo && pImportInfo->mtlSharedEvent) {
+		_mtlEvent = [pImportInfo->mtlSharedEvent retain];		// retained
+		_mtlEventValue = pImportInfo->mtlSharedEvent.signaledValue + 1;
+	} else if (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT) {
+		_mtlEvent = [device->getMTLDevice() newSharedEvent];	//retained
+		_mtlEventValue = ((id<MTLSharedEvent>)_mtlEvent).signaledValue + 1;
+	} else {
+		_mtlEvent = [device->getMTLDevice() newEvent];			//retained
+		_mtlEventValue = 1;
+	}
+}
 
 MVKSemaphoreMTLEvent::~MVKSemaphoreMTLEvent() {
     [_mtlEvent release];
@@ -164,9 +185,17 @@
 	encodeSignal(mtlCmdBuff, 0);
 }
 
-MVKSemaphoreEmulated::MVKSemaphoreEmulated(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo) :
+MVKSemaphoreEmulated::MVKSemaphoreEmulated(MVKDevice* device,
+										   const VkSemaphoreCreateInfo* pCreateInfo,
+										   const VkExportMetalObjectCreateInfoEXT* pExportInfo,
+										   const VkImportMetalSharedEventInfoEXT* pImportInfo) :
 	MVKSemaphore(device, pCreateInfo),
-	_blocker(false, 1) {}
+	_blocker(false, 1) {
+
+	if ((pImportInfo && pImportInfo->mtlSharedEvent) || (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT)) {
+		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkCreateEvent(): MTLSharedEvent is not available with VkSemaphores that use CPU emulation."));
+	}
+}
 
 
 #pragma mark -
@@ -215,11 +244,10 @@
 														   const VkSemaphoreCreateInfo* pCreateInfo,
 														   const VkSemaphoreTypeCreateInfo* pTypeCreateInfo,
 														   const VkExportMetalObjectCreateInfoEXT* pExportInfo,
-														   const VkImportMetalSharedEventInfoEXT* pImportInfo) :
-	MVKTimelineSemaphore(device, pCreateInfo, pTypeCreateInfo, pExportInfo, pImportInfo) {
+														   const VkImportMetalSharedEventInfoEXT* pImportInfo) : MVKTimelineSemaphore(device, pCreateInfo) {
 
 	// Import or create a Metal event
-	_mtlEvent = (pImportInfo
+	_mtlEvent = (pImportInfo && pImportInfo->mtlSharedEvent
 				 ? [pImportInfo->mtlSharedEvent retain]
 				 : [device->getMTLDevice() newSharedEvent]);	//retained
 
@@ -299,10 +327,10 @@
 														   const VkSemaphoreTypeCreateInfo* pTypeCreateInfo,
 														   const VkExportMetalObjectCreateInfoEXT* pExportInfo,
 														   const VkImportMetalSharedEventInfoEXT* pImportInfo) :
-	MVKTimelineSemaphore(device, pCreateInfo, pTypeCreateInfo, pExportInfo, pImportInfo),
+	MVKTimelineSemaphore(device, pCreateInfo),
 	_value(pTypeCreateInfo ? pTypeCreateInfo->initialValue : 0) {
 
-	if (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT) {
+	if ((pImportInfo && pImportInfo->mtlSharedEvent) || (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT)) {
 		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkCreateEvent(): MTLSharedEvent is not available on this platform."));
 	}
 }
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index 51b08b1..604a8cf 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -44,7 +44,7 @@
 MVK_EXTENSION(KHR_16bit_storage,                   KHR_16BIT_STORAGE,                    DEVICE,   10.11,  8.0)
 MVK_EXTENSION(KHR_8bit_storage,                    KHR_8BIT_STORAGE,                     DEVICE,   10.11,  8.0)
 MVK_EXTENSION(KHR_bind_memory2,                    KHR_BIND_MEMORY_2,                    DEVICE,   10.11,  8.0)
-MVK_EXTENSION(KHR_buffer_device_address,           KHR_BUFFER_DEVICE_ADDRESS,            DEVICE,    13.0, 16.0)
+MVK_EXTENSION(KHR_buffer_device_address,           KHR_BUFFER_DEVICE_ADDRESS,            DEVICE,   12.05,  16.0)
 MVK_EXTENSION(KHR_create_renderpass2,              KHR_CREATE_RENDERPASS_2,              DEVICE,   10.11,  8.0)
 MVK_EXTENSION(KHR_dedicated_allocation,            KHR_DEDICATED_ALLOCATION,             DEVICE,   10.11,  8.0)
 MVK_EXTENSION(KHR_depth_stencil_resolve,           KHR_DEPTH_STENCIL_RESOLVE,            DEVICE,   10.11,  8.0)
@@ -85,6 +85,7 @@
 MVK_EXTENSION(KHR_timeline_semaphore,              KHR_TIMELINE_SEMAPHORE,               DEVICE,   10.11,  8.0)
 MVK_EXTENSION(KHR_uniform_buffer_standard_layout,  KHR_UNIFORM_BUFFER_STANDARD_LAYOUT,   DEVICE,   10.11,  8.0)
 MVK_EXTENSION(KHR_variable_pointers,               KHR_VARIABLE_POINTERS,                DEVICE,   10.11,  8.0)
+MVK_EXTENSION(EXT_buffer_device_address,           EXT_BUFFER_DEVICE_ADDRESS,            DEVICE,   12.05,  16.0)
 MVK_EXTENSION(EXT_debug_marker,                    EXT_DEBUG_MARKER,                     DEVICE,   10.11,  8.0)
 MVK_EXTENSION(EXT_debug_report,                    EXT_DEBUG_REPORT,                     INSTANCE, 10.11,  8.0)
 MVK_EXTENSION(EXT_debug_utils,                     EXT_DEBUG_UTILS,                      INSTANCE, 10.11,  8.0)
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index 3d6964f..58b6c27 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -2802,6 +2802,12 @@
 
 
 #pragma mark -
+#pragma mark VK_EXT_buffer_device_address extension
+
+MVK_PUBLIC_VULKAN_ALIAS(vkGetBufferDeviceAddressEXT, vkGetBufferDeviceAddressKHR);
+
+
+#pragma mark -
 #pragma mark VK_EXT_debug_report extension
 
 MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCreateDebugReportCallbackEXT(