@@ -242,6 +242,15 @@ extern "C" {
242242 #endif
243243#endif
244244
245+ // Defined to 1 when VK_KHR_external_memory_win32 device extension is defined in Vulkan headers.
246+ #if !defined(VMA_EXTERNAL_MEMORY_WIN32)
247+ #if VK_KHR_external_memory_win32
248+ #define VMA_EXTERNAL_MEMORY_WIN32 1
249+ #else
250+ #define VMA_EXTERNAL_MEMORY_WIN32 0
251+ #endif
252+ #endif
253+
245254// Define these macros to decorate all public functions with additional code,
246255// before and after returned type, appropriately. This may be useful for
247256// exporting the functions when compiling VMA as a separate library. Example:
@@ -461,6 +470,14 @@ typedef enum VmaAllocatorCreateFlagBits
461470 */
462471 VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100,
463472
473+ /**
474+ Enables usage of VK_KHR_external_memory_win32 extension in the library.
475+
476+ You should set this flag if you found available and enabled this device extension,
477+ while creating Vulkan device passed as VmaAllocatorCreateInfo::device.
478+ */
479+ VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT = 0x00000200,
480+
464481 VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
465482} VmaAllocatorCreateFlagBits;
466483/// See #VmaAllocatorCreateFlagBits.
@@ -1035,6 +1052,11 @@ typedef struct VmaVulkanFunctions
10351052 /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4.
10361053 PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements;
10371054#endif
1055+ #ifdef VMA_EXTERNAL_MEMORY_WIN32
1056+ PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR;
1057+ #else
1058+ void* VMA_NULLABLE vkGetMemoryWin32HandleKHR;
1059+ #endif
10381060} VmaVulkanFunctions;
10391061
10401062/// Description of a Allocator to be created.
@@ -2052,6 +2074,21 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties(
20522074 VmaAllocation VMA_NOT_NULL allocation,
20532075 VkMemoryPropertyFlags* VMA_NOT_NULL pFlags);
20542076
2077+
2078+ #if VMA_EXTERNAL_MEMORY_WIN32
2079+ /**
2080+ \brief Given an allocation, returns Win32 Handle, that may be imported by other processes or APIs.
2081+
2082+ `hTargetProcess` must be a valid handle to target process or NULL. If it's `NULL`, the function returns
2083+ handle for the current process.
2084+
2085+ If the allocation was created with `VMA_ALLOCATION_CREATE_EXPORT_WIN32_HANDLE_BIT` flag,
2086+ the function fills `pHandle` with handle that can be used in target process.
2087+ */
2088+ VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator,
2089+ VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* VMA_NOT_NULL pHandle);
2090+ #endif // VMA_EXTERNAL_MEMORY_WIN32
2091+
20552092/** \brief Maps memory represented by given allocation and returns pointer to it.
20562093
20572094Maps memory represented by given allocation to make it accessible to CPU code.
@@ -6069,6 +6106,84 @@ class VmaMappingHysteresis
60696106
60706107#endif // _VMA_MAPPING_HYSTERESIS
60716108
6109+ #if VMA_EXTERNAL_MEMORY_WIN32
6110+ class VmaWin32Handle
6111+ {
6112+ public:
6113+ VmaWin32Handle() noexcept : m_hHandle(VMA_NULL) { }
6114+ explicit VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { }
6115+ ~VmaWin32Handle() noexcept { if (m_hHandle != VMA_NULL) { ::CloseHandle(m_hHandle); } }
6116+ VMA_CLASS_NO_COPY_NO_MOVE(VmaWin32Handle)
6117+
6118+ public:
6119+ // Strengthened
6120+ VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, bool useMutex, HANDLE* pHandle) noexcept
6121+ {
6122+ *pHandle = VMA_NULL;
6123+ // Try to get handle first.
6124+ if (m_hHandle != VMA_NULL)
6125+ {
6126+ *pHandle = Duplicate(hTargetProcess);
6127+ return VK_SUCCESS;
6128+ }
6129+
6130+ VkResult res = VK_SUCCESS;
6131+ // If failed, try to create it.
6132+ {
6133+ VmaMutexLockWrite lock(m_Mutex, useMutex);
6134+ if (m_hHandle == VMA_NULL)
6135+ {
6136+ res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &m_hHandle);
6137+ }
6138+ }
6139+
6140+ *pHandle = Duplicate(hTargetProcess);
6141+ return res;
6142+ }
6143+
6144+ operator bool() const noexcept { return m_hHandle != VMA_NULL; }
6145+ private:
6146+ // Not atomic
6147+ static VkResult Create(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE* pHandle) noexcept
6148+ {
6149+ VkResult res = VK_ERROR_FEATURE_NOT_PRESENT;
6150+ if (pvkGetMemoryWin32HandleKHR != VMA_NULL)
6151+ {
6152+ VkMemoryGetWin32HandleInfoKHR handleInfo{ };
6153+ handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
6154+ handleInfo.memory = memory;
6155+ handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
6156+ res = pvkGetMemoryWin32HandleKHR(device, &handleInfo, pHandle);
6157+ }
6158+ return res;
6159+ }
6160+ HANDLE Duplicate(HANDLE hTargetProcess = VMA_NULL) const noexcept
6161+ {
6162+ if (!m_hHandle)
6163+ return m_hHandle;
6164+
6165+ HANDLE hCurrentProcess = ::GetCurrentProcess();
6166+ HANDLE hDupHandle = VMA_NULL;
6167+ if (!::DuplicateHandle(hCurrentProcess, m_hHandle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
6168+ {
6169+ VMA_ASSERT(0 && "Failed to duplicate handle.");
6170+ }
6171+ return hDupHandle;
6172+ }
6173+ private:
6174+ HANDLE m_hHandle;
6175+ VMA_RW_MUTEX m_Mutex; // Protects access m_Handle
6176+ };
6177+ #else
6178+ class VmaWin32Handle
6179+ {
6180+ // ABI compatibility
6181+ void* placeholder = VMA_NULL;
6182+ VMA_RW_MUTEX placeholder2;
6183+ };
6184+ #endif // VMA_EXTERNAL_MEMORY_WIN32
6185+
6186+
60726187#ifndef _VMA_DEVICE_MEMORY_BLOCK
60736188/*
60746189Represents a single block of device memory (`VkDeviceMemory`) with all the
@@ -6135,7 +6250,13 @@ class VmaDeviceMemoryBlock
61356250 VkDeviceSize allocationLocalOffset,
61366251 VkImage hImage,
61376252 const void* pNext);
6138-
6253+ #if VMA_EXTERNAL_MEMORY_WIN32
6254+ VkResult CreateWin32Handle(
6255+ const VmaAllocator hAllocator,
6256+ decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR,
6257+ HANDLE hTargetProcess,
6258+ HANDLE* pHandle)noexcept;
6259+ #endif // VMA_EXTERNAL_MEMORY_WIN32
61396260private:
61406261 VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
61416262 uint32_t m_MemoryTypeIndex;
@@ -6151,6 +6272,8 @@ class VmaDeviceMemoryBlock
61516272 VmaMappingHysteresis m_MappingHysteresis;
61526273 uint32_t m_MapCount;
61536274 void* m_pMappedData;
6275+
6276+ VmaWin32Handle m_Handle; // Win32 handle
61546277};
61556278#endif // _VMA_DEVICE_MEMORY_BLOCK
61566279
@@ -6236,6 +6359,10 @@ struct VmaAllocation_T
62366359 void PrintParameters(class VmaJsonWriter& json) const;
62376360#endif
62386361
6362+ #if VMA_EXTERNAL_MEMORY_WIN32
6363+ VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) noexcept;
6364+ #endif // VMA_EXTERNAL_MEMORY_WIN32
6365+
62396366private:
62406367 // Allocation out of VmaDeviceMemoryBlock.
62416368 struct BlockAllocation
@@ -6251,6 +6378,7 @@ struct VmaAllocation_T
62516378 void* m_pMappedData; // Not null means memory is mapped.
62526379 VmaAllocation_T* m_Prev;
62536380 VmaAllocation_T* m_Next;
6381+ VmaWin32Handle m_Handle; // Win32 handle
62546382 };
62556383 union
62566384 {
@@ -10071,6 +10199,7 @@ struct VmaAllocator_T
1007110199 bool m_UseExtMemoryPriority;
1007210200 bool m_UseKhrMaintenance4;
1007310201 bool m_UseKhrMaintenance5;
10202+ bool m_UseKhrExternalMemoryWin32;
1007410203 const VkDevice m_hDevice;
1007510204 const VkInstance m_hInstance;
1007610205 const bool m_AllocationCallbacksSpecified;
@@ -10434,7 +10563,8 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator)
1043410563 m_Id(0),
1043510564 m_hMemory(VK_NULL_HANDLE),
1043610565 m_MapCount(0),
10437- m_pMappedData(VMA_NULL) {}
10566+ m_pMappedData(VMA_NULL),
10567+ m_Handle(VMA_NULL) {}
1043810568
1043910569VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock()
1044010570{
@@ -10677,6 +10807,14 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory(
1067710807 VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex);
1067810808 return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
1067910809}
10810+
10811+ #if VMA_EXTERNAL_MEMORY_WIN32
10812+ VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept
10813+ {
10814+ VMA_ASSERT(pHandle);
10815+ return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle);
10816+ }
10817+ #endif // VMA_EXTERNAL_MEMORY_WIN32
1068010818#endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS
1068110819
1068210820#ifndef _VMA_ALLOCATION_T_FUNCTIONS
@@ -10977,6 +11115,23 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
1097711115 json.WriteString(m_pName);
1097811116 }
1097911117}
11118+ #if VMA_EXTERNAL_MEMORY_WIN32
11119+ VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept
11120+ {
11121+ // Where do we get this function from?
11122+ auto pvkGetMemoryWin32HandleKHR = hAllocator->GetVulkanFunctions().vkGetMemoryWin32HandleKHR;
11123+ switch (m_Type)
11124+ {
11125+ case ALLOCATION_TYPE_BLOCK:
11126+ return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle);
11127+ case ALLOCATION_TYPE_DEDICATED:
11128+ return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle);
11129+ default:
11130+ VMA_ASSERT(0);
11131+ return VK_ERROR_FEATURE_NOT_PRESENT;
11132+ }
11133+ }
11134+ #endif // VMA_EXTERNAL_MEMORY_WIN32
1098011135#endif // VMA_STATS_STRING_ENABLED
1098111136
1098211137void VmaAllocation_T::FreeName(VmaAllocator hAllocator)
@@ -12707,6 +12862,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
1270712862 m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
1270812863 m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0),
1270912864 m_UseKhrMaintenance5((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0),
12865+ m_UseKhrExternalMemoryWin32((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT) != 0),
1271012866 m_hDevice(pCreateInfo->device),
1271112867 m_hInstance(pCreateInfo->instance),
1271212868 m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
@@ -12798,6 +12954,19 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
1279812954 VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
1279912955 }
1280012956#endif
12957+ #if !(VMA_KHR_MAINTENANCE5)
12958+ if(m_UseKhrMaintenance5)
12959+ {
12960+ VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
12961+ }
12962+ #endif
12963+
12964+ #if !(VMA_EXTERNAL_MEMORY_WIN32)
12965+ if(m_UseKhrExternalMemoryWin32)
12966+ {
12967+ VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
12968+ }
12969+ #endif
1280112970
1280212971 memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
1280312972 memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
@@ -13022,7 +13191,9 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul
1302213191 VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements);
1302313192 VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements);
1302413193#endif
13025-
13194+ #if VMA_EXTERNAL_MEMORY_WIN32
13195+ VMA_COPY_IF_NOT_NULL(vkGetMemoryWin32HandleKHR);
13196+ #endif
1302613197#undef VMA_COPY_IF_NOT_NULL
1302713198}
1302813199
@@ -13124,7 +13295,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
1312413295 VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR");
1312513296 }
1312613297#endif
13127-
13298+ #if VMA_EXTERNAL_MEMORY_WIN32
13299+ if (m_UseKhrExternalMemoryWin32)
13300+ {
13301+ VMA_FETCH_DEVICE_FUNC(vkGetMemoryWin32HandleKHR, PFN_vkGetMemoryWin32HandleKHR, "vkGetMemoryWin32HandleKHR");
13302+ }
13303+ #endif
1312813304#undef VMA_FETCH_DEVICE_FUNC
1312913305#undef VMA_FETCH_INSTANCE_FUNC
1313013306}
@@ -13173,6 +13349,12 @@ void VmaAllocator_T::ValidateVulkanFunctions()
1317313349 VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
1317413350 }
1317513351#endif
13352+ #if VMA_EXTERNAL_MEMORY_WIN32
13353+ if (m_UseKhrExternalMemoryWin32)
13354+ {
13355+ VMA_ASSERT(m_VulkanFunctions.vkGetMemoryWin32HandleKHR != VMA_NULL);
13356+ }
13357+ #endif
1317613358
1317713359 // Not validating these due to suspected driver bugs with these function
1317813360 // pointers being null despite correct extension or Vulkan version is enabled.
@@ -16429,6 +16611,15 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock V
1642916611 VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString);
1643016612 }
1643116613}
16614+ #if VMA_EXTERNAL_MEMORY_WIN32
16615+ VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator,
16616+ VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* VMA_NOT_NULL pHandle)
16617+ {
16618+ VMA_ASSERT(allocator && allocation);
16619+ VMA_DEBUG_GLOBAL_MUTEX_LOCK;
16620+ return allocation->GetWin32Handle(allocator, hTargetProcess, pHandle);
16621+ }
16622+ #endif // VMA_EXTERNAL_MEMORY_WIN32
1643216623#endif // VMA_STATS_STRING_ENABLED
1643316624#endif // _VMA_PUBLIC_INTERFACE
1643416625#endif // VMA_IMPLEMENTATION
0 commit comments