Merge pull request #442 from Agrael1/master

[WIP] Win32 Handle extension
This commit is contained in:
Adam Sawicki 2024-08-28 10:34:23 +02:00 committed by GitHub
commit 0d55cf5276
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 282 additions and 5 deletions

View File

@ -2466,6 +2466,7 @@ PREDEFINED = VMA_CALL_PRE= \
VMA_MEMORY_PRIORITY=1 \ VMA_MEMORY_PRIORITY=1 \
VMA_KHR_MAINTENANCE4=1 \ VMA_KHR_MAINTENANCE4=1 \
VMA_KHR_MAINTENANCE5=1 \ VMA_KHR_MAINTENANCE5=1 \
VMA_EXTERNAL_MEMORY_WIN32=1 \
VMA_EXTERNAL_MEMORY=1 \ VMA_EXTERNAL_MEMORY=1 \
VMA_EXTENDS_VK_STRUCT= \ VMA_EXTENDS_VK_STRUCT= \
VMA_STATS_STRING_ENABLED=1 VMA_STATS_STRING_ENABLED=1

View File

@ -242,6 +242,15 @@ extern "C" {
#endif #endif
#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, // Define these macros to decorate all public functions with additional code,
// before and after returned type, appropriately. This may be useful for // before and after returned type, appropriately. This may be useful for
// exporting the functions when compiling VMA as a separate library. Example: // 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, 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 VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VmaAllocatorCreateFlagBits; } VmaAllocatorCreateFlagBits;
/// See #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. /// 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; PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements;
#endif #endif
#ifdef VMA_EXTERNAL_MEMORY_WIN32
PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR;
#else
void* VMA_NULLABLE vkGetMemoryWin32HandleKHR;
#endif
} VmaVulkanFunctions; } VmaVulkanFunctions;
/// Description of a Allocator to be created. /// Description of a Allocator to be created.
@ -2052,6 +2074,21 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties(
VmaAllocation VMA_NOT_NULL allocation, VmaAllocation VMA_NOT_NULL allocation,
VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); 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. /** \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. Maps memory represented by given allocation to make it accessible to CPU code.
@ -6069,6 +6106,84 @@ private:
#endif // _VMA_MAPPING_HYSTERESIS #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 #ifndef _VMA_DEVICE_MEMORY_BLOCK
/* /*
Represents a single block of device memory (`VkDeviceMemory`) with all the Represents a single block of device memory (`VkDeviceMemory`) with all the
@ -6135,7 +6250,13 @@ public:
VkDeviceSize allocationLocalOffset, VkDeviceSize allocationLocalOffset,
VkImage hImage, VkImage hImage,
const void* pNext); 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: private:
VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
uint32_t m_MemoryTypeIndex; uint32_t m_MemoryTypeIndex;
@ -6151,6 +6272,8 @@ private:
VmaMappingHysteresis m_MappingHysteresis; VmaMappingHysteresis m_MappingHysteresis;
uint32_t m_MapCount; uint32_t m_MapCount;
void* m_pMappedData; void* m_pMappedData;
VmaWin32Handle m_Handle; // Win32 handle
}; };
#endif // _VMA_DEVICE_MEMORY_BLOCK #endif // _VMA_DEVICE_MEMORY_BLOCK
@ -6236,6 +6359,10 @@ public:
void PrintParameters(class VmaJsonWriter& json) const; void PrintParameters(class VmaJsonWriter& json) const;
#endif #endif
#if VMA_EXTERNAL_MEMORY_WIN32
VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) noexcept;
#endif // VMA_EXTERNAL_MEMORY_WIN32
private: private:
// Allocation out of VmaDeviceMemoryBlock. // Allocation out of VmaDeviceMemoryBlock.
struct BlockAllocation struct BlockAllocation
@ -6251,6 +6378,7 @@ private:
void* m_pMappedData; // Not null means memory is mapped. void* m_pMappedData; // Not null means memory is mapped.
VmaAllocation_T* m_Prev; VmaAllocation_T* m_Prev;
VmaAllocation_T* m_Next; VmaAllocation_T* m_Next;
VmaWin32Handle m_Handle; // Win32 handle
}; };
union union
{ {
@ -10071,6 +10199,7 @@ public:
bool m_UseExtMemoryPriority; bool m_UseExtMemoryPriority;
bool m_UseKhrMaintenance4; bool m_UseKhrMaintenance4;
bool m_UseKhrMaintenance5; bool m_UseKhrMaintenance5;
bool m_UseKhrExternalMemoryWin32;
const VkDevice m_hDevice; const VkDevice m_hDevice;
const VkInstance m_hInstance; const VkInstance m_hInstance;
const bool m_AllocationCallbacksSpecified; const bool m_AllocationCallbacksSpecified;
@ -10434,7 +10563,8 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator)
m_Id(0), m_Id(0),
m_hMemory(VK_NULL_HANDLE), m_hMemory(VK_NULL_HANDLE),
m_MapCount(0), m_MapCount(0),
m_pMappedData(VMA_NULL) {} m_pMappedData(VMA_NULL),
m_Handle(VMA_NULL) {}
VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock()
{ {
@ -10677,6 +10807,14 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory(
VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex);
return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); 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 #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS
#ifndef _VMA_ALLOCATION_T_FUNCTIONS #ifndef _VMA_ALLOCATION_T_FUNCTIONS
@ -10977,6 +11115,23 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
json.WriteString(m_pName); 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 #endif // VMA_STATS_STRING_ENABLED
void VmaAllocation_T::FreeName(VmaAllocator hAllocator) 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_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_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_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_hDevice(pCreateInfo->device),
m_hInstance(pCreateInfo->instance), m_hInstance(pCreateInfo->instance),
m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), 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."); 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 #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_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); 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(vkGetDeviceBufferMemoryRequirements);
VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements);
#endif #endif
#if VMA_EXTERNAL_MEMORY_WIN32
VMA_COPY_IF_NOT_NULL(vkGetMemoryWin32HandleKHR);
#endif
#undef VMA_COPY_IF_NOT_NULL #undef VMA_COPY_IF_NOT_NULL
} }
@ -13124,7 +13295,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR"); VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR");
} }
#endif #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_DEVICE_FUNC
#undef VMA_FETCH_INSTANCE_FUNC #undef VMA_FETCH_INSTANCE_FUNC
} }
@ -13173,6 +13349,12 @@ void VmaAllocator_T::ValidateVulkanFunctions()
VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
} }
#endif #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 // Not validating these due to suspected driver bugs with these function
// pointers being null despite correct extension or Vulkan version is enabled. // 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); 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_STATS_STRING_ENABLED
#endif // _VMA_PUBLIC_INTERFACE #endif // _VMA_PUBLIC_INTERFACE
#endif // VMA_IMPLEMENTATION #endif // VMA_IMPLEMENTATION

View File

@ -17,14 +17,22 @@ foreach(SHADER ${SHADERS})
get_filename_component(FILE_NAME ${SHADER} NAME) get_filename_component(FILE_NAME ${SHADER} NAME)
# Put the .spv files into the bin folder # Put the .spv files into the bin folder
set(SPIRV_BIN ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.spv)
set(SPIRV ${PROJECT_SOURCE_DIR}/bin/${FILE_NAME}.spv) set(SPIRV ${PROJECT_SOURCE_DIR}/bin/${FILE_NAME}.spv)
add_custom_command( add_custom_command(
OUTPUT ${SPIRV} OUTPUT ${SPIRV}
# Use the same file name and append .spv to the compiled shader # Use the same file name and append .spv to the compiled shader
COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV} COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV}
DEPENDS ${SHADER} DEPENDS ${SHADER}
) )
add_custom_command(
OUTPUT ${SPIRV_BIN}
# Use the same file name and append .spv to the compiled shader
COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV_BIN}
DEPENDS ${SHADER}
)
list(APPEND SPIRV_FILES ${SPIRV}) list(APPEND SPIRV_FILES ${SPIRV})
endforeach() endforeach()

View File

@ -8253,6 +8253,71 @@ static void TestMappingHysteresis()
} }
} }
static void TestWin32Handles()
{
#if VMA_EXTERNAL_MEMORY_WIN32
wprintf(L"Test Win32 handles\n");
constexpr static VkExportMemoryAllocateInfoKHR exportInfo{
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
nullptr,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
};
constexpr static VkExternalMemoryBufferCreateInfoKHR externalInfo{
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
nullptr,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
};
VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
sampleBufCreateInfo.size = 0x1000; // Doesn't matter.
sampleBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
sampleBufCreateInfo.pNext = &externalInfo;
VmaAllocationCreateInfo sampleAllocCreateInfo = {};
sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
sampleAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
uint32_t memTypeIndex;
TEST(vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator,
&sampleBufCreateInfo, &sampleAllocCreateInfo, &memTypeIndex) == VK_SUCCESS);
// Check res...
// Create a pool that can have at most 2 blocks, 128 MiB each.
VmaPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.memoryTypeIndex = memTypeIndex;
poolCreateInfo.blockSize = 128ull * 1024 * 1024;
poolCreateInfo.maxBlockCount = 2;
poolCreateInfo.pMemoryAllocateNext = (void*)&exportInfo;
VmaPool pool;
TEST(vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS);
sampleAllocCreateInfo.pool = pool;
VkBuffer buf;
VmaAllocation alloc;
VmaAllocationInfo allocInfo;
TEST(vmaCreateBuffer(g_hAllocator, &sampleBufCreateInfo, &sampleAllocCreateInfo, &buf, &alloc, &allocInfo) == VK_SUCCESS);
HANDLE handle;
HANDLE handle2;
TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle) == VK_SUCCESS);
TEST(handle != nullptr);
TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle2) == VK_SUCCESS);
TEST(handle2 != nullptr);
TEST(handle2 != handle);
vmaDestroyBuffer(g_hAllocator, buf, alloc);
TEST(CloseHandle(handle));
TEST(CloseHandle(handle2));
vmaDestroyPool(g_hAllocator, pool);
#endif
}
void Test() void Test()
{ {
wprintf(L"TESTING:\n"); wprintf(L"TESTING:\n");
@ -8295,6 +8360,7 @@ void Test()
TestMappingHysteresis(); TestMappingHysteresis();
TestDeviceLocalMapped(); TestDeviceLocalMapped();
TestMaintenance5(); TestMaintenance5();
TestWin32Handles();
TestMappingMultithreaded(); TestMappingMultithreaded();
TestLinearAllocator(); TestLinearAllocator();
ManuallyTestLinearAllocator(); ManuallyTestLinearAllocator();

View File

@ -32,7 +32,7 @@
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")
static const char* const SHADER_PATH1 = "./"; static const char* const SHADER_PATH1 = "./Shaders/";
static const char* const SHADER_PATH2 = "../bin/"; static const char* const SHADER_PATH2 = "../bin/";
static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE"; static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation"; static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
@ -69,6 +69,7 @@ bool VK_KHR_buffer_device_address_enabled = false;
bool VK_EXT_memory_priority_enabled = false; bool VK_EXT_memory_priority_enabled = false;
bool VK_EXT_debug_utils_enabled = false; bool VK_EXT_debug_utils_enabled = false;
bool VK_KHR_maintenance5_enabled = false; bool VK_KHR_maintenance5_enabled = false;
bool VK_KHR_external_memory_win32_enabled = false;
bool g_SparseBindingEnabled = false; bool g_SparseBindingEnabled = false;
// # Pointers to functions from extensions // # Pointers to functions from extensions
@ -1449,6 +1450,7 @@ static void PrintEnabledFeatures()
} }
wprintf(L"VK_EXT_memory_priority: %d\n", VK_EXT_memory_priority_enabled ? 1 : 0); wprintf(L"VK_EXT_memory_priority: %d\n", VK_EXT_memory_priority_enabled ? 1 : 0);
wprintf(L"VK_KHR_maintenance5: %d\n", VK_KHR_maintenance5_enabled? 1 : 0); wprintf(L"VK_KHR_maintenance5: %d\n", VK_KHR_maintenance5_enabled? 1 : 0);
wprintf(L"VK_KHR_external_memory_win32: %d\n", VK_KHR_external_memory_win32_enabled ? 1 : 0);
} }
void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo) void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
@ -1494,6 +1496,11 @@ void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT; outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT;
} }
if(VK_KHR_external_memory_win32_enabled)
{
outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT;
}
if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS) if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
{ {
outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks; outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
@ -1876,6 +1883,8 @@ static void InitializeApplication()
VK_EXT_memory_priority_enabled = true; VK_EXT_memory_priority_enabled = true;
else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_MAINTENANCE_5_EXTENSION_NAME) == 0) else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_MAINTENANCE_5_EXTENSION_NAME) == 0)
VK_KHR_maintenance5_enabled = true; VK_KHR_maintenance5_enabled = true;
else if (strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME) == 0)
VK_KHR_external_memory_win32_enabled = VMA_DYNAMIC_VULKAN_FUNCTIONS;
} }
if(GetVulkanApiVersion() >= VK_API_VERSION_1_2) if(GetVulkanApiVersion() >= VK_API_VERSION_1_2)
@ -2036,6 +2045,8 @@ static void InitializeApplication()
enabledDeviceExtensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME);
if(VK_KHR_maintenance5_enabled) if(VK_KHR_maintenance5_enabled)
enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
if (VK_KHR_external_memory_win32_enabled)
enabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
deviceFeatures.features.samplerAnisotropy = VK_TRUE; deviceFeatures.features.samplerAnisotropy = VK_TRUE;