Skip to content

Commit

Permalink
Add MTLHeaps export/import for emulated textures
Browse files Browse the repository at this point in the history
  • Loading branch information
aitor-lunarg committed Oct 16, 2024
1 parent e25fc84 commit 148967d
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 30 deletions.
2 changes: 1 addition & 1 deletion ExternalRevisions/Vulkan-Headers_repo_revision
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20c2e4fc5722e4ba9f95669448a62860c2a7fbd0
5a895c363dd689fdd58a4d336cceda77eca3a62f
6 changes: 5 additions & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,12 @@
_externalMemoryHandleTypes = handleTypes;
auto& xmProps = getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT);
_requiresDedicatedMemoryAllocation = _requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
} else if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT)) {
_externalMemoryHandleTypes = handleTypes;
auto& xmProps = getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT);
_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_EXT is supported."));
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateBuffer(): Only external memory handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT and VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT are supported."));
}
}

Expand Down
5 changes: 3 additions & 2 deletions MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject {
/** Returns the external memory properties supported for images for the handle type. */
VkExternalMemoryProperties& getExternalImageProperties(VkFormat format, VkExternalMemoryHandleTypeFlagBits handleType);

uint32_t getExternalResourceMemoryTypeBits(MTLResource_id handle) const;
uint32_t getExternalResourceMemoryTypeBits(VkExternalMemoryHandleTypeFlagBits handleType, void* handle) const;


#pragma mark Metal
Expand Down Expand Up @@ -464,6 +464,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject {
VkExternalMemoryProperties _hostPointerExternalMemoryProperties;
VkExternalMemoryProperties _mtlBufferExternalMemoryProperties;
VkExternalMemoryProperties _mtlTextureExternalMemoryProperties;
VkExternalMemoryProperties _mtlTextureHeapExternalMemoryProperties;
id<MTLCounterSet> _timestampMTLCounterSet;
MVKSemaphoreStyle _vkSemaphoreStyle;
MTLTimestamp _prevCPUTimestamp = 0;
Expand Down Expand Up @@ -821,7 +822,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject {
/** Returns the Metal objects underpinning the Vulkan objects indicated in the pNext chain of pMetalObjectsInfo. */
void getMetalObjects(VkExportMetalObjectsInfoEXT* pMetalObjectsInfo);

MTLResource_id getResourceIdFromHandle(const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo, MTLResource_id* pHandle) const;
void* getResourceIdFromHandle(const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo) const;


#pragma mark Construction
Expand Down
32 changes: 22 additions & 10 deletions MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1384,20 +1384,22 @@
return _hostPointerExternalMemoryProperties;
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT:
// We cannot export images that have no Metal counterparts. This is because we are emulating them via multiple MTLTextures
// and we would require to export multiple MTLTextures. A possible workaround would be to let the user export them as a
// MTLBuffer that covers all textures' memory. However, this would have limited usage since MoltenVK will only know what
// the layout of that MTLBuffer is and how to read it.
// and we would require to export multiple MTLTextures. We let them export them as a heap whenever possible.
if (_pixelFormats.getChromaSubsamplingPlaneCount(format) > 1u)
return _emptyExtMemProps;
return _mtlTextureHeapExternalMemoryProperties;
return _mtlTextureExternalMemoryProperties;
default:
return _emptyExtMemProps;
}
}

uint32_t MVKPhysicalDevice::getExternalResourceMemoryTypeBits(MTLResource_id handle) const {
uint32_t MVKPhysicalDevice::getExternalResourceMemoryTypeBits(VkExternalMemoryHandleTypeFlagBits handleType,
void* handle) const {
// MTLBuffer and MTLTextures are resources. MTLHeap is not according to Metal
const bool isResource = handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
const MTLStorageMode storageMode = isResource ? ((id<MTLResource>)handle).storageMode : ((id<MTLHeap>)handle).storageMode;
uint32_t memoryTypeBits = 0u;
switch (handle.storageMode) {
switch (storageMode) {
case MTLStorageModeShared:
memoryTypeBits = _hostCoherentMemoryTypes;
break;
Expand Down Expand Up @@ -3364,6 +3366,14 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope
VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
_mtlTextureExternalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT;
_mtlTextureExternalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT;

if (_metalFeatures.placementHeaps) {
_mtlTextureHeapExternalMemoryProperties = _mtlTextureExternalMemoryProperties;
_mtlTextureHeapExternalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
_mtlTextureHeapExternalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
} else {
_mtlTextureHeapExternalMemoryProperties = _emptyExtMemProps;
}
}

void MVKPhysicalDevice::initExtensions() {
Expand Down Expand Up @@ -4814,17 +4824,19 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope
}
}

MTLResource_id MVKDevice::getResourceIdFromHandle(const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo, MTLResource_id* pHandle) const
void* MVKDevice::getResourceIdFromHandle(const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo) const
{
MTLResource_id handle = nil;
void* handle = nil;
MVKDeviceMemory* memory = (MVKDeviceMemory*)pGetMetalHandleInfo->memory;
switch (pGetMetalHandleInfo->handleType) {
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT:
*pHandle = memory->getMTLBuffer();
handle = memory->getMTLBuffer();
break;
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT:
*pHandle = memory->getMTLTexture();
handle = memory->getMTLTexture();
break;
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT:
handle = memory->getMTLHeap();
default:
break;
}
Expand Down
25 changes: 19 additions & 6 deletions MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,15 @@
case VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT: {
const auto* pImportInfo = (VkImportMemoryMetalHandleInfoEXT*)next;
_externalMemoryHandleType = pImportInfo->handleType;
if (pImportInfo->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT) {
// This handle type will only be exposed to the user if we actually are supporting heaps
if (pImportInfo->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT) {
[_mtlHeap release];
_mtlHeap = [((id<MTLHeap>)pImportInfo->handle) retain];
_mtlStorageMode = _mtlHeap.storageMode;
_mtlCPUCacheMode = _mtlHeap.cpuCacheMode;
_allocationSize = _mtlHeap.size;
}
else if (pImportInfo->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT) {
[_mtlBuffer release]; // guard against dups
_mtlBuffer = [((id<MTLBuffer>)pImportInfo->handle) retain]; // retained
_mtlStorageMode = _mtlBuffer.storageMode;
Expand Down Expand Up @@ -395,11 +403,9 @@
}

// 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, "vkAllocateMemory(): Could not allocate VkDeviceMemory of size %llu bytes.", _allocationSize));
return;
}
if (!ensureMTLHeap()) {
setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "vkAllocateMemory(): Could not allocate VkDeviceMemory of size %llu bytes.", _allocationSize));
return;
}

// If memory needs to be coherent it must reside in a MTLBuffer, since an open-ended map() must work.
Expand All @@ -418,6 +424,13 @@
}

bool requiresDedicated = false;
if (mvkIsAnyFlagEnabled(_externalMemoryHandleType, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT)) {
auto& xmProps = getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT);
requiresDedicated = requiresDedicated || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);

// Make sure allocation happens at creation time since we may need to export the memory before usage
ensureMTLBuffer();
}
if (mvkIsAnyFlagEnabled(_externalMemoryHandleType, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT)) {
auto& xmProps = getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT);
requiresDedicated = requiresDedicated || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
Expand Down
18 changes: 12 additions & 6 deletions MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1384,13 +1384,19 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
void MVKImage::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
if ( !handleTypes ) { return; }
if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT)) {
auto& xmProps = getPhysicalDevice()->getExternalImageProperties(_vkFormat, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT);
for(auto& memoryBinding : _memoryBindings) {
memoryBinding->_externalMemoryHandleTypes = handleTypes;
memoryBinding->_requiresDedicatedMemoryAllocation = memoryBinding->_requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
}
auto& xmProps = getPhysicalDevice()->getExternalImageProperties(_vkFormat, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT);
for(auto& memoryBinding : _memoryBindings) {
memoryBinding->_externalMemoryHandleTypes = handleTypes;
memoryBinding->_requiresDedicatedMemoryAllocation = memoryBinding->_requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
}
} else if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT)) {
auto& xmProps = getPhysicalDevice()->getExternalImageProperties(_vkFormat, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT);
for(auto& memoryBinding : _memoryBindings) {
memoryBinding->_externalMemoryHandleTypes = handleTypes;
memoryBinding->_requiresDedicatedMemoryAllocation = memoryBinding->_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_EXT is supported."));
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage(): Only external memory handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT and VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT are supported."));
}
}

Expand Down
8 changes: 4 additions & 4 deletions MoltenVK/MoltenVK/Vulkan/vulkan.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3040,24 +3040,24 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkDestroyDeferredOperationKHR(
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMemoryMetalHandleEXT(
VkDevice device,
const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo,
MTLResource_id* pHandle) {
void** pHandle) {

MVKTraceVulkanCallStart();
MVKDevice* mvkDvc = MVKDevice::getMVKDevice(device);
mvkDvc->getResourceIdFromHandle(pGetMetalHandleInfo, pHandle);
*pHandle = mvkDvc->getResourceIdFromHandle(pGetMetalHandleInfo);
MVKTraceVulkanCallEnd();
return VK_SUCCESS;
}

MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMemoryMetalHandlePropertiesEXT(
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
MTLResource_id handle,
void* handle,
VkMemoryMetalHandlePropertiesEXT* pMemoryMetalHandleProperties) {

MVKTraceVulkanCallStart();
MVKDevice* mvkDvc = MVKDevice::getMVKDevice(device);
pMemoryMetalHandleProperties->memoryTypeBits = mvkDvc->getPhysicalDevice()->getExternalResourceMemoryTypeBits(handle);
pMemoryMetalHandleProperties->memoryTypeBits = mvkDvc->getPhysicalDevice()->getExternalResourceMemoryTypeBits(handleType, handle);
MVKTraceVulkanCallEnd();
return VK_SUCCESS;
}
Expand Down

0 comments on commit 148967d

Please sign in to comment.