-
Notifications
You must be signed in to change notification settings - Fork 429
[WIP] Win32 Handle extension #442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
746c651
33bd6c6
8c665c4
c41e3fb
9402a6b
65afd9e
0c8feb2
c9b2a6a
2683cfe
e962c8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -242,6 +242,15 @@ extern "C" { | |
| #endif | ||
| #endif | ||
|
|
||
| // Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. | ||
| #if !defined(VMA_EXTERNAL_MEMORY_WIN32) | ||
| #if VK_KHR_external_memory_win32 | ||
| #define VMA_EXTERNAL_MEMORY_WIN32 1 | ||
| #else | ||
| #define VMA_EXTERNAL_MEMORY_WIN32 0 | ||
| #endif | ||
| #endif | ||
|
|
||
| // Define these macros to decorate all public functions with additional code, | ||
| // before and after returned type, appropriately. This may be useful for | ||
| // exporting the functions when compiling VMA as a separate library. Example: | ||
|
|
@@ -461,6 +470,14 @@ typedef enum VmaAllocatorCreateFlagBits | |
| */ | ||
| VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, | ||
|
|
||
| /** | ||
| Enables usage of VK_KHR_external_memory_win32 extension in the library. | ||
|
|
||
| You should set this flag if you found available and enabled this device extension, | ||
| while creating Vulkan device passed as VmaAllocatorCreateInfo::device. | ||
| */ | ||
| VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT = 0x00000200, | ||
|
|
||
| VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF | ||
| } VmaAllocatorCreateFlagBits; | ||
| /// See #VmaAllocatorCreateFlagBits. | ||
|
|
@@ -1035,6 +1052,11 @@ typedef struct VmaVulkanFunctions | |
| /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. | ||
| PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; | ||
| #endif | ||
| #ifdef VK_USE_PLATFORM_WIN32_KHR | ||
| PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; | ||
| #else | ||
| void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; | ||
|
adam-sawicki-a marked this conversation as resolved.
|
||
| #endif | ||
| } VmaVulkanFunctions; | ||
|
|
||
| /// Description of a Allocator to be created. | ||
|
|
@@ -6069,6 +6091,91 @@ class VmaMappingHysteresis | |
|
|
||
| #endif // _VMA_MAPPING_HYSTERESIS | ||
|
|
||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| class VmaWin32Handle | ||
| { | ||
| public: | ||
| VmaWin32Handle() noexcept : m_hHandle(VMA_NULL) { } | ||
| VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { } | ||
|
adam-sawicki-a marked this conversation as resolved.
Outdated
|
||
| ~VmaWin32Handle() noexcept { if (m_hHandle != VMA_NULL) { ::CloseHandle(m_hHandle); } } | ||
| VMA_CLASS_NO_COPY_NO_MOVE(VmaWin32Handle) | ||
|
|
||
| public: | ||
| // Strengthened | ||
| VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, bool useMutex, HANDLE* pHandle) noexcept | ||
| { | ||
| *pHandle = VMA_NULL; | ||
| // We only care about atomicity of handle retrieval, not about memory order. | ||
| HANDLE handle = m_hHandle.load(std::memory_order_relaxed); | ||
|
|
||
| // Try to get handle first. | ||
| if (handle != VMA_NULL) | ||
| { | ||
| *pHandle = Duplicate(hTargetProcess); | ||
| return VK_SUCCESS; | ||
| } | ||
|
|
||
| HANDLE hCreatedHandle = VMA_NULL; | ||
|
|
||
| VkResult res = VK_SUCCESS; | ||
| // If failed, try to create it. | ||
| { | ||
| VmaMutexLockWrite lock(m_Mutex, useMutex); | ||
| if (m_hHandle.load(std::memory_order_relaxed) == VMA_NULL) | ||
| { | ||
| VkResult res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); | ||
| m_hHandle.store(hCreatedHandle, std::memory_order_relaxed); | ||
| } | ||
| } | ||
|
|
||
| *pHandle = Duplicate(hTargetProcess); | ||
| return res; | ||
| } | ||
|
adam-sawicki-a marked this conversation as resolved.
Outdated
|
||
|
|
||
| operator bool() const noexcept { return m_hHandle != VMA_NULL; } | ||
| private: | ||
| // Not atomic | ||
| static VkResult Create(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE* pHandle) noexcept | ||
| { | ||
| VkResult res = VK_ERROR_FEATURE_NOT_PRESENT; | ||
| if (pvkGetMemoryWin32HandleKHR != VMA_NULL) | ||
| { | ||
| VkMemoryGetWin32HandleInfoKHR handleInfo{ }; | ||
| handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; | ||
| handleInfo.memory = memory; | ||
| handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; | ||
| res = pvkGetMemoryWin32HandleKHR(device, &handleInfo, pHandle); | ||
| } | ||
| return res; | ||
| } | ||
| HANDLE Duplicate(HANDLE hTargetProcess = VMA_NULL) const noexcept | ||
| { | ||
| HANDLE handle = m_hHandle.load(std::memory_order_relaxed); | ||
| if (!handle) | ||
| return handle; | ||
|
|
||
| HANDLE hCurrentProcess = ::GetCurrentProcess(); | ||
| HANDLE hDupHandle = VMA_NULL; | ||
| if (!::DuplicateHandle(hCurrentProcess, handle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) | ||
| { | ||
| VMA_ASSERT(0 && "Failed to duplicate handle."); | ||
| } | ||
| return hDupHandle; | ||
| } | ||
| private: | ||
| std::atomic<HANDLE> m_hHandle; | ||
|
adam-sawicki-a marked this conversation as resolved.
Outdated
|
||
| VMA_RW_MUTEX m_Mutex; // Protects access m_Handle | ||
| }; | ||
| #else | ||
| class VmaWin32Handle | ||
|
adam-sawicki-a marked this conversation as resolved.
|
||
| { | ||
| // ABI compatibility | ||
| void* placeholder = VMA_NULL; | ||
| VMA_RW_MUTEX placeholder2; | ||
| }; | ||
| #endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
|
|
||
|
|
||
| #ifndef _VMA_DEVICE_MEMORY_BLOCK | ||
| /* | ||
| Represents a single block of device memory (`VkDeviceMemory`) with all the | ||
|
|
@@ -6135,7 +6242,13 @@ class VmaDeviceMemoryBlock | |
| VkDeviceSize allocationLocalOffset, | ||
| VkImage hImage, | ||
| const void* pNext); | ||
|
|
||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| VkResult CreateWin32Handle( | ||
| const VmaAllocator hAllocator, | ||
| decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, | ||
| HANDLE hTargetProcess, | ||
| HANDLE* pHandle)noexcept; | ||
| #endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
| private: | ||
| VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. | ||
| uint32_t m_MemoryTypeIndex; | ||
|
|
@@ -6151,6 +6264,8 @@ class VmaDeviceMemoryBlock | |
| VmaMappingHysteresis m_MappingHysteresis; | ||
| uint32_t m_MapCount; | ||
| void* m_pMappedData; | ||
|
|
||
| VmaWin32Handle m_Handle; // Win32 handle | ||
| }; | ||
| #endif // _VMA_DEVICE_MEMORY_BLOCK | ||
|
|
||
|
|
@@ -6236,6 +6351,10 @@ struct VmaAllocation_T | |
| void PrintParameters(class VmaJsonWriter& json) const; | ||
| #endif | ||
|
|
||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) const noexcept; | ||
| #endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
|
|
||
| private: | ||
| // Allocation out of VmaDeviceMemoryBlock. | ||
| struct BlockAllocation | ||
|
|
@@ -6251,6 +6370,7 @@ struct VmaAllocation_T | |
| void* m_pMappedData; // Not null means memory is mapped. | ||
| VmaAllocation_T* m_Prev; | ||
| VmaAllocation_T* m_Next; | ||
| mutable VmaWin32Handle m_Handle; // Win32 handle | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does it need
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically it'd be more correct to use mutable on HANDLE, since to the outside user state does not change, but I'll remove the const form function |
||
| }; | ||
| union | ||
| { | ||
|
|
@@ -10071,6 +10191,7 @@ struct VmaAllocator_T | |
| bool m_UseExtMemoryPriority; | ||
| bool m_UseKhrMaintenance4; | ||
| bool m_UseKhrMaintenance5; | ||
| bool m_UseKhrExternalMemoryWin32; | ||
| const VkDevice m_hDevice; | ||
| const VkInstance m_hInstance; | ||
| const bool m_AllocationCallbacksSpecified; | ||
|
|
@@ -10434,7 +10555,8 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) | |
| m_Id(0), | ||
| m_hMemory(VK_NULL_HANDLE), | ||
| m_MapCount(0), | ||
| m_pMappedData(VMA_NULL) {} | ||
| m_pMappedData(VMA_NULL), | ||
| m_Handle(VMA_NULL) {} | ||
|
|
||
| VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() | ||
| { | ||
|
|
@@ -10677,6 +10799,14 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory( | |
| VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); | ||
| return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); | ||
| } | ||
|
|
||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept | ||
| { | ||
| VMA_ASSERT(pHandle); | ||
| return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); | ||
| } | ||
| #endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
| #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS | ||
|
|
||
| #ifndef _VMA_ALLOCATION_T_FUNCTIONS | ||
|
|
@@ -10977,6 +11107,23 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const | |
| json.WriteString(m_pName); | ||
| } | ||
| } | ||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept | ||
| { | ||
| // Where do we get this function from? | ||
| auto pvkGetMemoryWin32HandleKHR = hAllocator->GetVulkanFunctions().vkGetMemoryWin32HandleKHR; | ||
| switch (m_Type) | ||
| { | ||
| case ALLOCATION_TYPE_BLOCK: | ||
| return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); | ||
| case ALLOCATION_TYPE_DEDICATED: | ||
| return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); | ||
| default: | ||
| VMA_ASSERT(0); | ||
| return VK_ERROR_FEATURE_NOT_PRESENT; | ||
| } | ||
| } | ||
| #endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
| #endif // VMA_STATS_STRING_ENABLED | ||
|
|
||
| void VmaAllocation_T::FreeName(VmaAllocator hAllocator) | ||
|
|
@@ -12707,6 +12854,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : | |
| m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), | ||
| m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), | ||
| m_UseKhrMaintenance5((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), | ||
| m_UseKhrExternalMemoryWin32((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT) != 0), | ||
| m_hDevice(pCreateInfo->device), | ||
| m_hInstance(pCreateInfo->instance), | ||
| m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), | ||
|
|
@@ -12798,6 +12946,19 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : | |
| 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."); | ||
| } | ||
| #endif | ||
| #if !(VMA_KHR_MAINTENANCE5) | ||
| if(m_UseKhrMaintenance5) | ||
| { | ||
| 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."); | ||
| } | ||
| #endif | ||
|
|
||
| #if !(VMA_EXTERNAL_MEMORY_WIN32) | ||
| if(m_UseKhrExternalMemoryWin32) | ||
| { | ||
| 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."); | ||
| } | ||
| #endif | ||
|
|
||
| memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); | ||
| memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); | ||
|
|
@@ -12973,6 +13134,11 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() | |
| m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; | ||
| } | ||
| #endif | ||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| m_VulkanFunctions.vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)vkGetMemoryWin32HandleKHR; | ||
| #else | ||
| m_VulkanFunctions.vkGetMemoryWin32HandleKHR = VMA_NULL; | ||
| #endif | ||
| } | ||
|
|
||
| #endif // VMA_STATIC_VULKAN_FUNCTIONS == 1 | ||
|
|
@@ -13022,7 +13188,9 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul | |
| VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements); | ||
| VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); | ||
| #endif | ||
|
|
||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| VMA_COPY_IF_NOT_NULL(vkGetMemoryWin32HandleKHR); | ||
| #endif | ||
| #undef VMA_COPY_IF_NOT_NULL | ||
| } | ||
|
|
||
|
|
@@ -13124,7 +13292,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() | |
| VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR"); | ||
| } | ||
| #endif | ||
|
|
||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| if (m_UseKhrExternalMemoryWin32) | ||
| { | ||
| VMA_FETCH_DEVICE_FUNC(vkGetMemoryWin32HandleKHR, PFN_vkGetMemoryWin32HandleKHR, "vkGetMemoryWin32HandleKHR"); | ||
| } | ||
| #endif | ||
| #undef VMA_FETCH_DEVICE_FUNC | ||
| #undef VMA_FETCH_INSTANCE_FUNC | ||
| } | ||
|
|
@@ -13173,6 +13346,12 @@ void VmaAllocator_T::ValidateVulkanFunctions() | |
| VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); | ||
| } | ||
| #endif | ||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| if (m_UseKhrExternalMemoryWin32) | ||
| { | ||
| VMA_ASSERT(m_VulkanFunctions.vkGetMemoryWin32HandleKHR != VMA_NULL); | ||
| } | ||
| #endif | ||
|
|
||
| // Not validating these due to suspected driver bugs with these function | ||
| // pointers being null despite correct extension or Vulkan version is enabled. | ||
|
|
@@ -16429,6 +16608,15 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock V | |
| VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString); | ||
| } | ||
| } | ||
| #if VMA_EXTERNAL_MEMORY_WIN32 | ||
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, | ||
| VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* pHandle) | ||
| { | ||
| VMA_ASSERT(allocator && allocation); | ||
| VMA_DEBUG_GLOBAL_MUTEX_LOCK; | ||
| return allocation->GetWin32Handle(allocator, hTargetProcess, pHandle); | ||
| } | ||
| #endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
| #endif // VMA_STATS_STRING_ENABLED | ||
| #endif // _VMA_PUBLIC_INTERFACE | ||
| #endif // VMA_IMPLEMENTATION | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.