@@ -242,6 +242,15 @@ extern "C" {
242
242
#endif
243
243
#endif
244
244
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
+
245
254
// Define these macros to decorate all public functions with additional code,
246
255
// before and after returned type, appropriately. This may be useful for
247
256
// exporting the functions when compiling VMA as a separate library. Example:
@@ -461,6 +470,14 @@ typedef enum VmaAllocatorCreateFlagBits
461
470
*/
462
471
VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100,
463
472
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
+
464
481
VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
465
482
} VmaAllocatorCreateFlagBits;
466
483
/// See #VmaAllocatorCreateFlagBits.
@@ -1035,6 +1052,11 @@ typedef struct VmaVulkanFunctions
1035
1052
/// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4.
1036
1053
PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements;
1037
1054
#endif
1055
+ #ifdef VMA_EXTERNAL_MEMORY_WIN32
1056
+ PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR;
1057
+ #else
1058
+ void* VMA_NULLABLE vkGetMemoryWin32HandleKHR;
1059
+ #endif
1038
1060
} VmaVulkanFunctions;
1039
1061
1040
1062
/// Description of a Allocator to be created.
@@ -2052,6 +2074,21 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties(
2052
2074
VmaAllocation VMA_NOT_NULL allocation,
2053
2075
VkMemoryPropertyFlags* VMA_NOT_NULL pFlags);
2054
2076
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
+
2055
2092
/** \brief Maps memory represented by given allocation and returns pointer to it.
2056
2093
2057
2094
Maps memory represented by given allocation to make it accessible to CPU code.
@@ -6069,6 +6106,84 @@ class VmaMappingHysteresis
6069
6106
6070
6107
#endif // _VMA_MAPPING_HYSTERESIS
6071
6108
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
+
6072
6187
#ifndef _VMA_DEVICE_MEMORY_BLOCK
6073
6188
/*
6074
6189
Represents a single block of device memory (`VkDeviceMemory`) with all the
@@ -6135,7 +6250,13 @@ class VmaDeviceMemoryBlock
6135
6250
VkDeviceSize allocationLocalOffset,
6136
6251
VkImage hImage,
6137
6252
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
6139
6260
private:
6140
6261
VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
6141
6262
uint32_t m_MemoryTypeIndex;
@@ -6151,6 +6272,8 @@ class VmaDeviceMemoryBlock
6151
6272
VmaMappingHysteresis m_MappingHysteresis;
6152
6273
uint32_t m_MapCount;
6153
6274
void* m_pMappedData;
6275
+
6276
+ VmaWin32Handle m_Handle; // Win32 handle
6154
6277
};
6155
6278
#endif // _VMA_DEVICE_MEMORY_BLOCK
6156
6279
@@ -6236,6 +6359,10 @@ struct VmaAllocation_T
6236
6359
void PrintParameters(class VmaJsonWriter& json) const;
6237
6360
#endif
6238
6361
6362
+ #if VMA_EXTERNAL_MEMORY_WIN32
6363
+ VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) noexcept;
6364
+ #endif // VMA_EXTERNAL_MEMORY_WIN32
6365
+
6239
6366
private:
6240
6367
// Allocation out of VmaDeviceMemoryBlock.
6241
6368
struct BlockAllocation
@@ -6251,6 +6378,7 @@ struct VmaAllocation_T
6251
6378
void* m_pMappedData; // Not null means memory is mapped.
6252
6379
VmaAllocation_T* m_Prev;
6253
6380
VmaAllocation_T* m_Next;
6381
+ VmaWin32Handle m_Handle; // Win32 handle
6254
6382
};
6255
6383
union
6256
6384
{
@@ -10071,6 +10199,7 @@ struct VmaAllocator_T
10071
10199
bool m_UseExtMemoryPriority;
10072
10200
bool m_UseKhrMaintenance4;
10073
10201
bool m_UseKhrMaintenance5;
10202
+ bool m_UseKhrExternalMemoryWin32;
10074
10203
const VkDevice m_hDevice;
10075
10204
const VkInstance m_hInstance;
10076
10205
const bool m_AllocationCallbacksSpecified;
@@ -10434,7 +10563,8 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator)
10434
10563
m_Id(0),
10435
10564
m_hMemory(VK_NULL_HANDLE),
10436
10565
m_MapCount(0),
10437
- m_pMappedData(VMA_NULL) {}
10566
+ m_pMappedData(VMA_NULL),
10567
+ m_Handle(VMA_NULL) {}
10438
10568
10439
10569
VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock()
10440
10570
{
@@ -10677,6 +10807,14 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory(
10677
10807
VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex);
10678
10808
return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
10679
10809
}
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
10680
10818
#endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS
10681
10819
10682
10820
#ifndef _VMA_ALLOCATION_T_FUNCTIONS
@@ -10977,6 +11115,23 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
10977
11115
json.WriteString(m_pName);
10978
11116
}
10979
11117
}
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
10980
11135
#endif // VMA_STATS_STRING_ENABLED
10981
11136
10982
11137
void VmaAllocation_T::FreeName(VmaAllocator hAllocator)
@@ -12707,6 +12862,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
12707
12862
m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
12708
12863
m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0),
12709
12864
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),
12710
12866
m_hDevice(pCreateInfo->device),
12711
12867
m_hInstance(pCreateInfo->instance),
12712
12868
m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
@@ -12798,6 +12954,19 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
12798
12954
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.");
12799
12955
}
12800
12956
#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
12801
12970
12802
12971
memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
12803
12972
memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
@@ -13022,7 +13191,9 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul
13022
13191
VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements);
13023
13192
VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements);
13024
13193
#endif
13025
-
13194
+ #if VMA_EXTERNAL_MEMORY_WIN32
13195
+ VMA_COPY_IF_NOT_NULL(vkGetMemoryWin32HandleKHR);
13196
+ #endif
13026
13197
#undef VMA_COPY_IF_NOT_NULL
13027
13198
}
13028
13199
@@ -13124,7 +13295,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
13124
13295
VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR");
13125
13296
}
13126
13297
#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
13128
13304
#undef VMA_FETCH_DEVICE_FUNC
13129
13305
#undef VMA_FETCH_INSTANCE_FUNC
13130
13306
}
@@ -13173,6 +13349,12 @@ void VmaAllocator_T::ValidateVulkanFunctions()
13173
13349
VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
13174
13350
}
13175
13351
#endif
13352
+ #if VMA_EXTERNAL_MEMORY_WIN32
13353
+ if (m_UseKhrExternalMemoryWin32)
13354
+ {
13355
+ VMA_ASSERT(m_VulkanFunctions.vkGetMemoryWin32HandleKHR != VMA_NULL);
13356
+ }
13357
+ #endif
13176
13358
13177
13359
// Not validating these due to suspected driver bugs with these function
13178
13360
// 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
16429
16611
VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString);
16430
16612
}
16431
16613
}
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
16432
16623
#endif // VMA_STATS_STRING_ENABLED
16433
16624
#endif // _VMA_PUBLIC_INTERFACE
16434
16625
#endif // VMA_IMPLEMENTATION
0 commit comments