Skip to content

Commit 0d55cf5

Browse files
Merge pull request #442 from Agrael1/master
[WIP] Win32 Handle extension
2 parents b8e5747 + e962c8c commit 0d55cf5

File tree

5 files changed

+282
-5
lines changed

5 files changed

+282
-5
lines changed

Doxyfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,6 +2466,7 @@ PREDEFINED = VMA_CALL_PRE= \
24662466
VMA_MEMORY_PRIORITY=1 \
24672467
VMA_KHR_MAINTENANCE4=1 \
24682468
VMA_KHR_MAINTENANCE5=1 \
2469+
VMA_EXTERNAL_MEMORY_WIN32=1 \
24692470
VMA_EXTERNAL_MEMORY=1 \
24702471
VMA_EXTENDS_VK_STRUCT= \
24712472
VMA_STATS_STRING_ENABLED=1

include/vk_mem_alloc.h

Lines changed: 195 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

20572094
Maps 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
/*
60746189
Represents 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
61396260
private:
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+
62396366
private:
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

1043910569
VmaDeviceMemoryBlock::~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

1098211137
void 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

src/Shaders/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,22 @@ foreach(SHADER ${SHADERS})
1717
get_filename_component(FILE_NAME ${SHADER} NAME)
1818

1919
# Put the .spv files into the bin folder
20+
set(SPIRV_BIN ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.spv)
2021
set(SPIRV ${PROJECT_SOURCE_DIR}/bin/${FILE_NAME}.spv)
2122

23+
2224
add_custom_command(
2325
OUTPUT ${SPIRV}
2426
# Use the same file name and append .spv to the compiled shader
2527
COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV}
2628
DEPENDS ${SHADER}
2729
)
30+
add_custom_command(
31+
OUTPUT ${SPIRV_BIN}
32+
# Use the same file name and append .spv to the compiled shader
33+
COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV_BIN}
34+
DEPENDS ${SHADER}
35+
)
2836

2937
list(APPEND SPIRV_FILES ${SPIRV})
3038
endforeach()

0 commit comments

Comments
 (0)