@@ -6077,41 +6077,85 @@ class VmaWin32Handle
60776077 VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { }
60786078 ~VmaWin32Handle() noexcept { if (m_hHandle != VMA_NULL) { ::CloseHandle(m_hHandle); } }
60796079 VMA_CLASS_NO_COPY_NO_MOVE(VmaWin32Handle)
6080+
60806081public:
6081- VkResult Init(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) vkGetMemoryWin32HandleKHR) noexcept
6082+ // Strengthened
6083+ VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept
6084+ {
6085+ *pHandle = VMA_NULL;
6086+ // We only care about atomicity of handle retrieval, not about memory order.
6087+ HANDLE handle = m_hHandle.load(std::memory_order_relaxed);
6088+
6089+ // Try to get handle first.
6090+ if (handle != VMA_NULL)
6091+ {
6092+ *pHandle = Duplicate(hTargetProcess);
6093+ return VK_SUCCESS;
6094+ }
6095+
6096+ HANDLE hCreatedHandle = VMA_NULL;
6097+
6098+ // If failed, try to create it.
6099+ VkResult res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle);
6100+ if (res == VK_SUCCESS)
6101+ {
6102+ // Successfully created handle, try to set it.
6103+ if (!m_hHandle.compare_exchange_strong(handle, hCreatedHandle, std::memory_order_relaxed))
6104+ {
6105+ // AMD workaround
6106+ if (hCreatedHandle != m_hHandle.load(std::memory_order_relaxed))
6107+ {
6108+ ::CloseHandle(hCreatedHandle);
6109+ }
6110+ }
6111+ }
6112+
6113+ // If somehow it was set in the meantime, return it.
6114+ if (m_hHandle.load(std::memory_order_relaxed))
6115+ {
6116+ *pHandle = Duplicate(hTargetProcess);
6117+ return VK_SUCCESS;
6118+ }
6119+ return res;
6120+ }
6121+
6122+ operator bool() const noexcept { return m_hHandle != VMA_NULL; }
6123+ private:
6124+ // Not atomic
6125+ static VkResult Create(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE* pHandle) noexcept
60826126 {
60836127 VkResult res = VK_ERROR_FEATURE_NOT_PRESENT;
6084- if (vkGetMemoryWin32HandleKHR != VMA_NULL)
6128+ if (pvkGetMemoryWin32HandleKHR != VMA_NULL)
60856129 {
60866130 VkMemoryGetWin32HandleInfoKHR handleInfo{ };
60876131 handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
60886132 handleInfo.memory = memory;
60896133 handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
6090- res = vkGetMemoryWin32HandleKHR (device, &handleInfo, &m_hHandle );
6134+ res = pvkGetMemoryWin32HandleKHR (device, &handleInfo, pHandle );
60916135 }
60926136 return res;
60936137 }
60946138 HANDLE Duplicate(HANDLE hTargetProcess = VMA_NULL) const noexcept
60956139 {
6096- if (!m_hHandle)
6097- return m_hHandle;
6140+ HANDLE handle = m_hHandle.load(std::memory_order_relaxed);
6141+ if (!handle)
6142+ return handle;
60986143
60996144 HANDLE hCurrentProcess = ::GetCurrentProcess();
61006145 HANDLE hDupHandle = VMA_NULL;
6101- if (!::DuplicateHandle(hCurrentProcess, m_hHandle , hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
6146+ if (!::DuplicateHandle(hCurrentProcess, handle , hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
61026147 {
61036148 VMA_ASSERT(0 && "Failed to duplicate handle.");
61046149 }
61056150 return hDupHandle;
61066151 }
6107- operator bool() const noexcept { return m_hHandle != VMA_NULL; }
6108-
61096152private:
6110- HANDLE m_hHandle;
6153+ std::atomic< HANDLE> m_hHandle;
61116154};
61126155#else
61136156class VmaWin32Handle
61146157{
6158+ // ABI compatibility
61156159 void* placeholder = VMA_NULL;
61166160};
61176161#endif // VK_USE_PLATFORM_WIN32_KHR
@@ -6186,6 +6230,7 @@ class VmaDeviceMemoryBlock
61866230#ifdef VK_USE_PLATFORM_WIN32_KHR
61876231 VkResult CreateWin32Handle(
61886232 const VmaAllocator hAllocator,
6233+ decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR,
61896234 HANDLE hTargetProcess,
61906235 HANDLE* pHandle)noexcept;
61916236#endif // VK_USE_PLATFORM_WIN32_KHR
@@ -6310,7 +6355,7 @@ struct VmaAllocation_T
63106355 void* m_pMappedData; // Not null means memory is mapped.
63116356 VmaAllocation_T* m_Prev;
63126357 VmaAllocation_T* m_Next;
6313- VmaWin32Handle m_Handle; // Win32 handle
6358+ mutable VmaWin32Handle m_Handle; // Win32 handle
63146359 };
63156360 union
63166361 {
@@ -10740,34 +10785,10 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory(
1074010785}
1074110786
1074210787#ifdef VK_USE_PLATFORM_WIN32_KHR
10743- VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept
10788+ VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept
1074410789{
1074510790 VMA_ASSERT(pHandle);
10746- *pHandle = VMA_NULL;
10747-
10748- // relieves the mutex
10749- if (m_Handle)
10750- {
10751- *pHandle = m_Handle.Duplicate(hTargetProcess);
10752- return VK_SUCCESS;
10753- }
10754-
10755- VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex);
10756- if (m_Handle)
10757- {
10758- *pHandle = m_Handle.Duplicate(hTargetProcess);
10759- return VK_SUCCESS;
10760- }
10761-
10762- // Do we pass the function manually or use the one from the allocator?
10763- VkResult res = m_Handle.Init(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR);
10764- if (res != VK_SUCCESS)
10765- {
10766- return res;
10767- }
10768-
10769- *pHandle = m_Handle.Duplicate(hTargetProcess);
10770- return VK_SUCCESS;
10791+ return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, pHandle);
1077110792}
1077210793#endif // VK_USE_PLATFORM_WIN32_KHR
1077310794#endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS
@@ -11071,14 +11092,16 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
1107111092 }
1107211093}
1107311094#ifdef VK_USE_PLATFORM_WIN32_KHR
11074- inline VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept
11095+ VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept
1107511096{
11097+ // Where do we get this function from?
11098+ auto pvkGetMemoryWin32HandleKHR = &vkGetMemoryWin32HandleKHR;
1107611099 switch (m_Type)
1107711100 {
1107811101 case ALLOCATION_TYPE_BLOCK:
11079- return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, hTargetProcess, pHandle);
11102+ return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle);
1108011103 case ALLOCATION_TYPE_DEDICATED:
11081- // return m_DedicatedAllocation.m_hMemory;
11104+ return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation. m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle) ;
1108211105 default:
1108311106 VMA_ASSERT(0);
1108411107 return VK_ERROR_FEATURE_NOT_PRESENT;
0 commit comments