diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index 86d2e8d3..fde73c5c 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -162,3 +162,5 @@ uint64_t mvkGetAvailableMemorySize(); /** Returns the amount of memory currently used by this process. */ uint64_t mvkGetUsedMemorySize(); +/** Returns the size of a page of host memory on this platform. */ +uint64_t mvkGetHostMemoryPageSize(); diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 2999870c..6c023086 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -136,3 +136,5 @@ uint64_t mvkGetUsedMemorySize() { return 0; } +uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); } + diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index cfa4e142..79027beb 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -356,6 +356,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_descriptor_indexing` *(initial release limited to Metal Tier 1: 96/128 textures, 16 samplers, except macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU, and if Metal argument buffers enabled in config)* +- `VK_EXT_external_memory_host` - `VK_EXT_fragment_shader_interlock` *(requires Metal 2.0 and Raster Order Groups)* - `VK_EXT_host_query_reset` - `VK_EXT_image_robustness` diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 0bba8b25..82698ee6 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -19,6 +19,7 @@ MoltenVK 1.2.3 Released TBA - Add support for extensions: + - `VK_EXT_external_memory_host` - `VK_EXT_pipeline_creation_cache_control` - `VK_EXT_shader_atomic_float` - `VK_EXT_surface_maintenance1` diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 66a3fede..44a5be5a 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -1023,6 +1023,7 @@ typedef struct { VkBool32 shaderBarycentricCoordinates; /**< If true, fragment shader barycentric coordinates are supported. */ MTLArgumentBuffersTier argumentBuffersTier; /**< The argument buffer tier available on this device, as a Metal enumeration. */ VkBool32 needsSampleDrefLodArrayWorkaround; /**< If true, sampling from arrayed depth images with explicit LoD is broken and needs a workaround. */ + VkDeviceSize hostMemoryPageSize; /**< The size of a page of host memory on this platform. */ } MVKPhysicalDeviceMetalFeatures; /** MoltenVK performance of a particular type of activity. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index c9b0e97e..22f8649e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -444,6 +444,7 @@ protected: uint32_t _hostCoherentMemoryTypes; uint32_t _privateMemoryTypes; uint32_t _lazilyAllocatedMemoryTypes; + VkExternalMemoryProperties _hostPointerExternalMemoryProperties; VkExternalMemoryProperties _mtlBufferExternalMemoryProperties; VkExternalMemoryProperties _mtlTextureExternalMemoryProperties; }; @@ -514,6 +515,11 @@ public: /** Populates the device group peer memory features. */ void getPeerMemoryFeatures(uint32_t heapIndex, uint32_t localDevice, uint32_t remoteDevice, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + /** Returns the properties of the host memory pointer. */ + VkResult getMemoryHostPointerProperties(VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHostPointer, + VkMemoryHostPointerPropertiesEXT* pMemHostPtrProps); + #pragma mark Object lifecycle diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 6a0bd6f2..3494740e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -694,9 +694,16 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) { portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment; break; } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { - auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next; - divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: { + auto* extMemHostProps = (VkPhysicalDeviceExternalMemoryHostPropertiesEXT*)next; + extMemHostProps->minImportedHostPointerAlignment = _metalFeatures.hostMemoryPageSize; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: { + // This isn't implemented yet, but when it is, it is expected that we'll wind up doing it manually. + auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next; + robustness2Props->robustStorageBufferAccessSizeAlignment = 1; + robustness2Props->robustUniformBufferAccessSizeAlignment = 1; break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: { @@ -709,11 +716,9 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) { sampLocnProps->variableSampleLocations = VK_FALSE; break; } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: { - // This isn't implemented yet, but when it is, it is expected that we'll wind up doing it manually. - auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next; - robustness2Props->robustStorageBufferAccessSizeAlignment = 1; - robustness2Props->robustUniformBufferAccessSizeAlignment = 1; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { + auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next; + divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32; break; } default: @@ -1055,15 +1060,25 @@ static VkExternalMemoryProperties _emptyExtMemProps = {}; VkExternalMemoryProperties& MVKPhysicalDevice::getExternalBufferProperties(VkExternalMemoryHandleTypeFlagBits handleType) { switch (handleType) { - case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR: return _mtlBufferExternalMemoryProperties; - default: return _emptyExtMemProps; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT: + return _hostPointerExternalMemoryProperties; + 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; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT: + return _hostPointerExternalMemoryProperties; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR: + return _mtlTextureExternalMemoryProperties; + default: + return _emptyExtMemProps; } } @@ -1599,6 +1614,8 @@ void MVKPhysicalDevice::initMetalFeatures() { // Start with all Metal features cleared mvkClear(&_metalFeatures); + _metalFeatures.hostMemoryPageSize = mvkGetHostMemoryPageSize(); + _metalFeatures.maxPerStageBufferCount = 31; _metalFeatures.maxMTLBufferSize = (256 * MEBI); _metalFeatures.dynamicMTLBufferSize = 0; @@ -2993,6 +3010,12 @@ uint32_t MVKPhysicalDevice::getMaxSamplerCount() { void MVKPhysicalDevice::initExternalMemoryProperties() { + // Common + _hostPointerExternalMemoryProperties.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + _hostPointerExternalMemoryProperties.exportFromImportedHandleTypes = 0; + _hostPointerExternalMemoryProperties.compatibleHandleTypes = (VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT); + // Buffers _mtlBufferExternalMemoryProperties.externalMemoryFeatures = (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT); @@ -3469,6 +3492,23 @@ void MVKDevice::getPeerMemoryFeatures(uint32_t heapIndex, uint32_t localDevice, *pPeerMemoryFeatures = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT | VK_PEER_MEMORY_FEATURE_COPY_DST_BIT; } +VkResult MVKDevice::getMemoryHostPointerProperties(VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHostPointer, + VkMemoryHostPointerPropertiesEXT* pMemHostPtrProps) { + if (pMemHostPtrProps) { + switch (handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT: + pMemHostPtrProps->memoryTypeBits = _physicalDevice->getHostVisibleMemoryTypes(); + break; + default: + pMemHostPtrProps->memoryTypeBits = 0; + break; + } + } + return VK_SUCCESS; +} + #pragma mark Object lifecycle diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h index 2f428e36..848984af 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h @@ -170,6 +170,7 @@ protected: MTLStorageMode _mtlStorageMode; MTLCPUCacheMode _mtlCPUCacheMode; bool _isDedicated = false; + bool _isHostMemImported = false; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm index 0eb447f4..d475a030 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm @@ -181,6 +181,9 @@ bool MVKDeviceMemory::ensureMTLHeap() { if (_mtlHeap) { return true; } + // Can't create a MTLHeap on a imported memory + if (_isHostMemImported) { return true; } + // Don't bother if we don't have placement heaps. if (!getDevice()->_pMetalFeatures->placementHeaps) { return true; } @@ -233,7 +236,12 @@ bool MVKDeviceMemory::ensureMTLBuffer() { } [_mtlBuffer makeAliasable]; } else if (_pHostMemory) { - _mtlBuffer = [getMTLDevice() newBufferWithBytes: _pHostMemory length: memLen options: getMTLResourceOptions()]; // retained + auto rezOpts = getMTLResourceOptions(); + if (_isHostMemImported) { + _mtlBuffer = [getMTLDevice() newBufferWithBytesNoCopy: _pHostMemory length: memLen options: rezOpts deallocator: nil]; // retained + } else { + _mtlBuffer = [getMTLDevice() newBufferWithBytes: _pHostMemory length: memLen options: rezOpts]; // retained + } freeHostMemory(); } else { _mtlBuffer = [getMTLDevice() newBufferWithLength: memLen options: getMTLResourceOptions()]; // retained @@ -264,7 +272,7 @@ bool MVKDeviceMemory::ensureHostMemory() { } void MVKDeviceMemory::freeHostMemory() { - free(_pHostMemory); + if ( !_isHostMemImported ) { free(_pHostMemory); } _pHostMemory = nullptr; } @@ -296,6 +304,23 @@ MVKDeviceMemory::MVKDeviceMemory(MVKDevice* device, _isDedicated = dedicatedImage || dedicatedBuffer; break; } + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: { + auto* pMemHostPtrInfo = (VkImportMemoryHostPointerInfoEXT*)next; + if (mvkIsAnyFlagEnabled(_vkMemPropFlags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + switch (pMemHostPtrInfo->handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT: + _pHostMemory = pMemHostPtrInfo->pHostPointer; + _isHostMemImported = true; + break; + default: + break; + } + } else { + setConfigurationResult(reportError(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR, "vkAllocateMemory(): Imported memory must be host-visible.")); + } + break; + } case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: { auto* pExpMemInfo = (VkExportMemoryAllocateInfo*)next; handleTypes = pExpMemInfo->handleTypes; @@ -333,7 +358,7 @@ MVKDeviceMemory::MVKDeviceMemory(MVKDevice* device, #if MVK_MACOS if (isMemoryHostCoherent() ) { if (!((MVKImage*)dedicatedImage)->_isLinear) { - setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Host-coherent VkDeviceMemory objects cannot be associated with optimal-tiling images.")); + setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "vkAllocateMemory(): Host-coherent VkDeviceMemory objects cannot be associated with optimal-tiling images.")); } else { if (!_device->_pMetalFeatures->sharedLinearTextures) { // Need to use the managed mode for images. @@ -341,7 +366,7 @@ MVKDeviceMemory::MVKDeviceMemory(MVKDevice* device, } // Nonetheless, we need a buffer to be able to map the memory at will. if (!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)); + setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "vkAllocateMemory(): 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)); } } } @@ -359,15 +384,16 @@ MVKDeviceMemory::MVKDeviceMemory(MVKDevice* device, // 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)); + 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 an MTLBuffer, since an open-ended map() must work. + // If memory needs to be coherent it must reside in a MTLBuffer, since an open-ended map() must work. + // If memory was imported, a MTLBuffer must be created on it. // Or if a MTLBuffer will be exported, ensure it exists. - if ((isMemoryHostCoherent() || willExportMTLBuffer) && !ensureMTLBuffer() ) { - setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not allocate a host-coherent or exportable VkDeviceMemory of size %llu bytes. The maximum memory-aligned size of a host-coherent VkDeviceMemory is %llu bytes.", _allocationSize, _device->_pMetalFeatures->maxMTLBufferSize)); + if ((isMemoryHostCoherent() || _isHostMemImported || willExportMTLBuffer) && !ensureMTLBuffer() ) { + setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "vkAllocateMemory(): Could not allocate a host-coherent or exportable VkDeviceMemory of size %llu bytes. The maximum memory-aligned size of a host-coherent VkDeviceMemory is %llu bytes.", _allocationSize, _device->_pMetalFeatures->maxMTLBufferSize)); } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index dc953db5..4d5f3c92 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -721,6 +721,7 @@ void MVKInstance::initProcAddrs() { ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerEndEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerInsertEXT, EXT_DEBUG_MARKER); + ADD_DVC_EXT_ENTRY_POINT(vkGetMemoryHostPointerPropertiesEXT, EXT_EXTERNAL_MEMORY_HOST); ADD_DVC_EXT_ENTRY_POINT(vkSetHdrMetadataEXT, EXT_HDR_METADATA); ADD_DVC_EXT_ENTRY_POINT(vkExportMetalObjectsEXT, EXT_METAL_OBJECTS); ADD_DVC_EXT_ENTRY_POINT(vkCreatePrivateDataSlotEXT, EXT_PRIVATE_DATA); diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index efedcbc2..515029c9 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, 13.0, 16.0) MVK_EXTENSION(KHR_copy_commands2, KHR_COPY_COMMANDS_2, DEVICE, 10.11, 8.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) @@ -91,11 +91,12 @@ MVK_EXTENSION(KHR_timeline_semaphore, KHR_TIMELINE_SEMAPHORE, 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(KHR_vulkan_memory_model, KHR_VULKAN_MEMORY_MODEL, DEVICE, MVK_NA, MVK_NA) -MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 16.0) +MVK_EXTENSION(EXT_buffer_device_address, EXT_BUFFER_DEVICE_ADDRESS, DEVICE, 13.0, 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) MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0) +MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0) MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0) MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA) MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0) diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 03abf9b9..d3c365a4 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -3228,6 +3228,23 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkSubmitDebugUtilsMessageEXT( } +#pragma mark - +#pragma mark VK_EXT_external_memory_host extension + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMemoryHostPointerPropertiesEXT( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHostPointer, + VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties) { + + MVKTraceVulkanCallStart(); + MVKDevice* mvkDvc = MVKDevice::getMVKDevice(device); + VkResult rslt = mvkDvc->getMemoryHostPointerProperties(handleType, pHostPointer, pMemoryHostPointerProperties); + MVKTraceVulkanCallEnd(); + return rslt; +} + + #pragma mark - #pragma mark VK_EXT_hdr_metadata extension