Merge pull request #1854 from billhollings/ext-external_memory_host
Add support for VK_EXT_external_memory_host extension.
This commit is contained in:
commit
dd5ff2a9b0
@ -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();
|
||||
|
@ -136,3 +136,5 @@ uint64_t mvkGetUsedMemorySize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); }
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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`
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -170,6 +170,7 @@ protected:
|
||||
MTLStorageMode _mtlStorageMode;
|
||||
MTLCPUCacheMode _mtlCPUCacheMode;
|
||||
bool _isDedicated = false;
|
||||
bool _isHostMemImported = false;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -96,6 +96,7 @@ MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER,
|
||||
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)
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user