Add support for VK_KHR_external_memory extension.
Functions and functionality supported, but don't currently do anything
until Metal-friendly enumerations added to VkExternalMemoryHandleTypeFlagBits.
Updated What's New document.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 2ddaa6f..2b7845c 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -20,7 +20,10 @@
Released TBD
- Add support for extensions:
- - `VK_KHR_external_memory_capabilities`
+ - `VK_KHR_external_memory` (non-functional groundwork for future
+ Metal-resource Vulkan extension).
+ - `VK_KHR_external_memory_capabilities` (non-functional groundwork
+ for future Metal-resource Vulkan extension).
- Memory consumption improvements when handling Vulkan commands.
- Reinstate `VulkanSamples API-Samples` demo apps and add
`input_attachment` and `push_descriptors` demos.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
index d3cbb05..60a2ac7 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
@@ -92,6 +92,7 @@
bool shouldFlushHostMemory();
VkResult flushToDevice(VkDeviceSize offset, VkDeviceSize size);
VkResult pullFromDevice(VkDeviceSize offset, VkDeviceSize size);
+ void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
VkBufferUsageFlags _usage;
bool _isHostCoherentTexelBuffer = false;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
index ed74605..4ce1465 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
@@ -66,8 +66,8 @@
switch (next->sType) {
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
auto* dedicatedReqs = (VkMemoryDedicatedRequirements*)next;
- dedicatedReqs->prefersDedicatedAllocation = VK_FALSE;
- dedicatedReqs->requiresDedicatedAllocation = VK_FALSE;
+ dedicatedReqs->requiresDedicatedAllocation = _requiresDedicatedMemoryAllocation;
+ dedicatedReqs->prefersDedicatedAllocation = dedicatedReqs->requiresDedicatedAllocation;
break;
}
default:
@@ -192,6 +192,28 @@
MVKBuffer::MVKBuffer(MVKDevice* device, const VkBufferCreateInfo* pCreateInfo) : MVKResource(device), _usage(pCreateInfo->usage) {
_byteAlignment = _device->_pMetalFeatures->mtlBufferAlignment;
_byteCount = pCreateInfo->size;
+
+ for (const auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO: {
+ auto* pExtMemInfo = (const VkExternalMemoryBufferCreateInfo*)next;
+ initExternalMemory(pExtMemInfo->handleTypes);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void MVKBuffer::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
+ if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR)) {
+ _externalMemoryHandleTypes = handleTypes;
+ auto& xmProps = _device->getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR);
+ _requiresDedicatedMemoryAllocation = _requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+ } else {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateBuffer(): Only external memory handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR is supported."));
+ }
}
MVKBuffer::~MVKBuffer() {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index 4bcc63b..f5e1f4d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -283,6 +283,12 @@
/** Returns whether this is a unified memory device. */
bool getHasUnifiedMemory();
+ /** Returns the external memory properties supported for buffers for the handle type. */
+ VkExternalMemoryProperties& getExternalBufferProperties(VkExternalMemoryHandleTypeFlagBits handleType);
+
+ /** Returns the external memory properties supported for images for the handle type. */
+ VkExternalMemoryProperties& getExternalImageProperties(VkExternalMemoryHandleTypeFlagBits handleType);
+
#pragma mark Metal
@@ -337,6 +343,7 @@
uint64_t getVRAMSize();
uint64_t getRecommendedMaxWorkingSetSize();
uint64_t getCurrentAllocatedSize();
+ void initExternalMemoryProperties();
void initExtensions();
MVKVector<MVKQueueFamily*>& getQueueFamilies();
void initPipelineCacheUUID();
@@ -344,9 +351,6 @@
uint64_t getSpirvCrossRevision();
bool getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo);
void populate(VkPhysicalDeviceIDProperties* pDevIdProps);
- void populate(VkExternalMemoryProperties& xmProps,
- VkExternalMemoryHandleTypeFlagBits handleType,
- VkExternalMemoryHandleTypeFlagBits supportedHandleType);
void logGPUInfo();
id<MTLDevice> _mtlDevice;
@@ -364,6 +368,8 @@
uint32_t _hostCoherentMemoryTypes;
uint32_t _privateMemoryTypes;
uint32_t _lazilyAllocatedMemoryTypes;
+ VkExternalMemoryProperties _mtlBufferExternalMemoryProperties;
+ VkExternalMemoryProperties _mtlTextureExternalMemoryProperties;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 79a3db4..00b8b42 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -419,10 +419,7 @@
for (auto* nextProps = (VkBaseOutStructure*)pImageFormatProperties->pNext; nextProps; nextProps = nextProps->pNext) {
if (nextProps->sType == VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES) {
auto* pExtImgFmtProps = (VkExternalImageFormatProperties*)nextProps;
-
- // TODO: This is an inoperable placeholder until VK_KHR_external_memory_metal is ratified and implemented
- const VkExternalMemoryHandleTypeFlagBits VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
- populate(pExtImgFmtProps->externalMemoryProperties, pExtImgFmtInfo->handleType, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR);
+ pExtImgFmtProps->externalMemoryProperties = getExternalImageProperties(pExtImgFmtInfo->handleType);
}
}
break;
@@ -482,24 +479,22 @@
void MVKPhysicalDevice::getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
VkExternalBufferProperties* pExternalBufferProperties) {
-
- // TODO: This is an inoperable placeholder until VK_KHR_external_memory_metal is ratified and implemented
- const VkExternalMemoryHandleTypeFlagBits VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
- populate(pExternalBufferProperties->externalMemoryProperties, pExternalBufferInfo->handleType, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR);
+ pExternalBufferProperties->externalMemoryProperties = getExternalBufferProperties(pExternalBufferInfo->handleType);
}
-// If the handleType is the supported handle type, populates xmProps accordingly, otherwise xmProps is cleared.
-void MVKPhysicalDevice::populate(VkExternalMemoryProperties& xmProps,
- VkExternalMemoryHandleTypeFlagBits handleType,
- VkExternalMemoryHandleTypeFlagBits supportedHandleType) {
- if (handleType == supportedHandleType) {
- xmProps.externalMemoryFeatures = (VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT |
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);
- xmProps.exportFromImportedHandleTypes = supportedHandleType;
- xmProps.compatibleHandleTypes = supportedHandleType;
- } else {
- mvkClear(&xmProps);
+static VkExternalMemoryProperties _emptyExtMemProps = {};
+
+VkExternalMemoryProperties& MVKPhysicalDevice::getExternalBufferProperties(VkExternalMemoryHandleTypeFlagBits handleType) {
+ switch (handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR: return _mtlBufferExternalMemoryProperties;
+ default: return _emptyExtMemProps;
+ }
+}
+
+VkExternalMemoryProperties& MVKPhysicalDevice::getExternalImageProperties(VkExternalMemoryHandleTypeFlagBits handleType) {
+ switch (handleType) {
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR: return _mtlTextureExternalMemoryProperties;
+ default: return _emptyExtMemProps;
}
}
@@ -847,8 +842,9 @@
initMetalFeatures(); // Call first.
initFeatures(); // Call second.
initProperties(); // Call third.
- initMemoryProperties();
initExtensions();
+ initMemoryProperties();
+ initExternalMemoryProperties();
logGPUInfo();
}
@@ -1973,6 +1969,23 @@
#endif
}
+void MVKPhysicalDevice::initExternalMemoryProperties() {
+
+ // Buffers
+ _mtlBufferExternalMemoryProperties.externalMemoryFeatures = (VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT |
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);
+ _mtlBufferExternalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR;
+ _mtlBufferExternalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR;
+
+ // Images
+ _mtlTextureExternalMemoryProperties.externalMemoryFeatures = (VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT |
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);
+ _mtlTextureExternalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+ _mtlTextureExternalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+}
+
void MVKPhysicalDevice::initExtensions() {
MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_supportedExtensions;
pWritableExtns->disableAllButEnabledDeviceExtensions();
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
index 5fc2cb2..0a51525 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
@@ -27,6 +27,10 @@
class MVKBuffer;
class MVKImage;
+// TODO: These are inoperable placeholders until VK_KHR_external_memory_metal defines them properly
+static const VkExternalMemoryHandleTypeFlagBits VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
+static const VkExternalMemoryHandleTypeFlagBits VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
+
#pragma mark MVKDeviceMemory
@@ -141,6 +145,7 @@
bool ensureHostMemory();
void freeHostMemory();
MVKResource* getDedicatedResource();
+ void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
MVKVectorInline<MVKBuffer*, 4> _buffers;
MVKVectorInline<MVKImage*, 4> _images;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
index 714a8f9..efcce8d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
@@ -266,10 +266,7 @@
MVKResource* MVKDeviceMemory::getDedicatedResource() {
MVKAssert(_isDedicated, "This method should only be called on dedicated allocations!");
- if (_buffers.empty())
- return _images[0];
- else
- return _buffers[0];
+ return _buffers.empty() ? (MVKResource*)_images[0] : (MVKResource*)_buffers[0];
}
MVKDeviceMemory::MVKDeviceMemory(MVKDevice* device,
@@ -284,22 +281,28 @@
VkImage dedicatedImage = VK_NULL_HANDLE;
VkBuffer dedicatedBuffer = VK_NULL_HANDLE;
- auto* next = (VkStructureType*)pAllocateInfo->pNext;
- while (next) {
- switch (*next) {
- case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
- auto* pDedicatedInfo = (VkMemoryDedicatedAllocateInfo*)next;
- dedicatedImage = pDedicatedInfo->image;
- dedicatedBuffer = pDedicatedInfo->buffer;
- next = (VkStructureType*)pDedicatedInfo->pNext;
- break;
- }
- default:
- next = (VkStructureType*)((VkMemoryAllocateInfo*)next)->pNext;
- break;
+ VkExternalMemoryHandleTypeFlags handleTypes = 0;
+ for (const auto* next = (const VkBaseInStructure*)pAllocateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
+ auto* pDedicatedInfo = (VkMemoryDedicatedAllocateInfo*)next;
+ dedicatedImage = pDedicatedInfo->image;
+ dedicatedBuffer = pDedicatedInfo->buffer;
+ _isDedicated = dedicatedImage || dedicatedBuffer;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: {
+ auto* pExpMemInfo = (VkExportMemoryAllocateInfo*)next;
+ handleTypes = pExpMemInfo->handleTypes;
+ break;
+ }
+ default:
+ break;
}
}
+ initExternalMemory(handleTypes); // After setting _isDedicated
+
// "Dedicated" means this memory can only be used for this image or buffer.
if (dedicatedImage) {
#if MVK_MACOS
@@ -316,14 +319,16 @@
}
}
#endif
- _isDedicated = true;
_images.push_back((MVKImage*)dedicatedImage);
return;
}
- // If we can, create a MTLHeap. This should happen before creating the buffer
- // allowing us to map its contents.
- if (!dedicatedImage && !dedicatedBuffer) {
+ if (dedicatedBuffer) {
+ _buffers.push_back((MVKBuffer*)dedicatedBuffer);
+ }
+
+ // If we can, create a MTLHeap. This should happen before creating the buffer, allowing us to map its contents.
+ if ( !_isDedicated ) {
if (!ensureMTLHeap()) {
setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not allocate VkDeviceMemory of size %llu bytes.", _allocationSize));
return;
@@ -334,10 +339,26 @@
if (isMemoryHostCoherent() && !ensureMTLBuffer() ) {
setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not allocate a host-coherent VkDeviceMemory of size %llu bytes. The maximum memory-aligned size of a host-coherent VkDeviceMemory is %llu bytes.", _allocationSize, _device->_pMetalFeatures->maxMTLBufferSize));
}
+}
- if (dedicatedBuffer) {
- _isDedicated = true;
- _buffers.push_back((MVKBuffer*)dedicatedBuffer);
+void MVKDeviceMemory::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
+ if ( !handleTypes ) { return; }
+
+ if ( !mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR) ) {
+ setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkAllocateMemory(): Only external memory handle types VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR or VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR are supported."));
+ }
+
+ bool requiresDedicated = false;
+ if (mvkIsAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR)) {
+ auto& xmProps = _device->getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR);
+ requiresDedicated = requiresDedicated || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+ }
+ if (mvkIsAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR)) {
+ auto& xmProps = _device->getPhysicalDevice()->getExternalImageProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR);
+ requiresDedicated = requiresDedicated || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+ }
+ if (requiresDedicated && !_isDedicated) {
+ setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkAllocateMemory(): External memory requires a dedicated VkBuffer or VkImage."));
}
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index 89e5af0..6772d56 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -235,6 +235,7 @@
bool validateUseTexelBuffer();
void initSubresources(const VkImageCreateInfo* pCreateInfo);
void initSubresourceLayout(MVKImageSubresource& imgSubRez);
+ void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
id<MTLTexture> newMTLTexture();
void releaseMTLTexture();
void releaseIOSurface();
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 0fdd941..0b378d7 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -182,8 +182,9 @@
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
auto* dedicatedReqs = (VkMemoryDedicatedRequirements*)next;
bool writable = mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
- dedicatedReqs->prefersDedicatedAllocation = !_usesTexelBuffer && (writable || !_device->_pMetalFeatures->placementHeaps);
- dedicatedReqs->requiresDedicatedAllocation = VK_FALSE;
+ dedicatedReqs->requiresDedicatedAllocation = _requiresDedicatedMemoryAllocation;
+ dedicatedReqs->prefersDedicatedAllocation = (dedicatedReqs->requiresDedicatedAllocation ||
+ (!_usesTexelBuffer && (writable || !_device->_pMetalFeatures->placementHeaps)));
break;
}
default:
@@ -615,6 +616,18 @@
}
initSubresources(pCreateInfo);
+
+ for (const auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO: {
+ auto* pExtMemInfo = (const VkExternalMemoryImageCreateInfo*)next;
+ initExternalMemory(pExtMemInfo->handleTypes);
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
@@ -784,6 +797,16 @@
layout.depthPitch = bytesPerLayerCurrLevel;
}
+void MVKImage::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
+ if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR)) {
+ _externalMemoryHandleTypes = handleTypes;
+ auto& xmProps = _device->getPhysicalDevice()->getExternalImageProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR);
+ _requiresDedicatedMemoryAllocation = _requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+ } else {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage(): Only external memory handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR is supported."));
+ }
+}
+
MVKImage::~MVKImage() {
if (_deviceMemory) { _deviceMemory->removeImage(this); }
releaseMTLTexture();
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKResource.h b/MoltenVK/MoltenVK/GPUObjects/MVKResource.h
index 3f5c235..766b769 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKResource.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKResource.h
@@ -88,4 +88,6 @@
VkDeviceSize _deviceMemoryOffset = 0;
VkDeviceSize _byteCount = 0;
VkDeviceSize _byteAlignment = 0;
+ VkExternalMemoryHandleTypeFlags _externalMemoryHandleTypes = 0;
+ bool _requiresDedicatedMemoryAllocation = false;
};
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index 337b802..f1b4580 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -46,6 +46,7 @@
MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE)
MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE)
MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE)
+MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE)
MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE)
MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE)
MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE)