-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
[WIP] Win32 Handle extension
- Loading branch information
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_win32 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 VMA_EXTERNAL_MEMORY_WIN32 | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
Mrkol
|
||
PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; | ||
#else | ||
void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; | ||
#endif | ||
} VmaVulkanFunctions; | ||
|
||
/// Description of a Allocator to be created. | ||
|
@@ -2052,6 +2074,21 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( | |
VmaAllocation VMA_NOT_NULL allocation, | ||
VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); | ||
|
||
|
||
#if VMA_EXTERNAL_MEMORY_WIN32 | ||
/** | ||
\brief Given an allocation, returns Win32 Handle, that may be imported by other processes or APIs. | ||
|
||
`hTargetProcess` must be a valid handle to target process or NULL. If it's `NULL`, the function returns | ||
handle for the current process. | ||
|
||
If the allocation was created with `VMA_ALLOCATION_CREATE_EXPORT_WIN32_HANDLE_BIT` flag, | ||
the function fills `pHandle` with handle that can be used in target process. | ||
*/ | ||
VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, | ||
VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* VMA_NOT_NULL pHandle); | ||
#endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
|
||
/** \brief Maps memory represented by given allocation and returns pointer to it. | ||
|
||
Maps memory represented by given allocation to make it accessible to CPU code. | ||
|
@@ -6069,6 +6106,84 @@ class VmaMappingHysteresis | |
|
||
#endif // _VMA_MAPPING_HYSTERESIS | ||
|
||
#if VMA_EXTERNAL_MEMORY_WIN32 | ||
class VmaWin32Handle | ||
{ | ||
public: | ||
VmaWin32Handle() noexcept : m_hHandle(VMA_NULL) { } | ||
explicit VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { } | ||
~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; | ||
// Try to get handle first. | ||
if (m_hHandle != VMA_NULL) | ||
{ | ||
*pHandle = Duplicate(hTargetProcess); | ||
return VK_SUCCESS; | ||
} | ||
|
||
VkResult res = VK_SUCCESS; | ||
// If failed, try to create it. | ||
{ | ||
VmaMutexLockWrite lock(m_Mutex, useMutex); | ||
if (m_hHandle == VMA_NULL) | ||
{ | ||
res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &m_hHandle); | ||
} | ||
} | ||
|
||
*pHandle = Duplicate(hTargetProcess); | ||
return res; | ||
} | ||
|
||
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 | ||
{ | ||
if (!m_hHandle) | ||
return m_hHandle; | ||
|
||
HANDLE hCurrentProcess = ::GetCurrentProcess(); | ||
HANDLE hDupHandle = VMA_NULL; | ||
if (!::DuplicateHandle(hCurrentProcess, m_hHandle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) | ||
{ | ||
VMA_ASSERT(0 && "Failed to duplicate handle."); | ||
} | ||
return hDupHandle; | ||
} | ||
private: | ||
HANDLE m_hHandle; | ||
VMA_RW_MUTEX m_Mutex; // Protects access m_Handle | ||
}; | ||
#else | ||
class VmaWin32Handle | ||
{ | ||
// 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 +6250,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 +6272,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 +6359,10 @@ struct VmaAllocation_T | |
void PrintParameters(class VmaJsonWriter& json) const; | ||
#endif | ||
|
||
#if VMA_EXTERNAL_MEMORY_WIN32 | ||
VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) noexcept; | ||
#endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
|
||
private: | ||
// Allocation out of VmaDeviceMemoryBlock. | ||
struct BlockAllocation | ||
|
@@ -6251,6 +6378,7 @@ struct VmaAllocation_T | |
void* m_pMappedData; // Not null means memory is mapped. | ||
VmaAllocation_T* m_Prev; | ||
VmaAllocation_T* m_Next; | ||
VmaWin32Handle m_Handle; // Win32 handle | ||
}; | ||
union | ||
{ | ||
|
@@ -10071,6 +10199,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 +10563,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 +10807,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, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); | ||
} | ||
#endif // VMA_EXTERNAL_MEMORY_WIN32 | ||
#endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS | ||
|
||
#ifndef _VMA_ALLOCATION_T_FUNCTIONS | ||
|
@@ -10977,6 +11115,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) 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 +12862,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 +12954,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)); | ||
|
@@ -13022,7 +13191,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 +13295,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 +13349,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 +16611,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* VMA_NOT_NULL 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 | ||
|
This is wrong and it breaks all linux builds (including my CI 💢), should be
#if VMA_EXTERNAL_MEMORY_WIN32
, because it's defined as 0 for systems that don't have it, not undefined completely!!!