Fixes after merge for VK_KHR_external_memory_win32 support

This commit is contained in:
Adam Sawicki 2024-08-28 11:43:13 +02:00
parent 0d55cf5276
commit ca17831d74
4 changed files with 92 additions and 55 deletions

View File

@ -6273,11 +6273,17 @@ private:
uint32_t m_MapCount; uint32_t m_MapCount;
void* m_pMappedData; void* m_pMappedData;
VmaWin32Handle m_Handle; // Win32 handle VmaWin32Handle m_Handle;
}; };
#endif // _VMA_DEVICE_MEMORY_BLOCK #endif // _VMA_DEVICE_MEMORY_BLOCK
#ifndef _VMA_ALLOCATION_T #ifndef _VMA_ALLOCATION_T
struct VmaAllocationExtraData
{
void* m_pMappedData = VMA_NULL; // Not null means memory is mapped.
VmaWin32Handle m_Handle;
};
struct VmaAllocation_T struct VmaAllocation_T
{ {
friend struct VmaDedicatedAllocationListItemTraits; friend struct VmaDedicatedAllocationListItemTraits;
@ -6310,12 +6316,14 @@ public:
bool mapped); bool mapped);
// pMappedData not null means allocation is created with MAPPED flag. // pMappedData not null means allocation is created with MAPPED flag.
void InitDedicatedAllocation( void InitDedicatedAllocation(
VmaAllocator allocator,
VmaPool hParentPool, VmaPool hParentPool,
uint32_t memoryTypeIndex, uint32_t memoryTypeIndex,
VkDeviceMemory hMemory, VkDeviceMemory hMemory,
VmaSuballocationType suballocationType, VmaSuballocationType suballocationType,
void* pMappedData, void* pMappedData,
VkDeviceSize size); VkDeviceSize size);
void Destroy(VmaAllocator allocator);
ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; } ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
VkDeviceSize GetAlignment() const { return m_Alignment; } VkDeviceSize GetAlignment() const { return m_Alignment; }
@ -6375,10 +6383,9 @@ 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.
VkDeviceMemory m_hMemory; VkDeviceMemory m_hMemory;
void* m_pMappedData; // Not null means memory is mapped. VmaAllocationExtraData* m_ExtraData;
VmaAllocation_T* m_Prev; VmaAllocation_T* m_Prev;
VmaAllocation_T* m_Next; VmaAllocation_T* m_Next;
VmaWin32Handle m_Handle; // Win32 handle
}; };
union union
{ {
@ -6401,6 +6408,8 @@ private:
#if VMA_STATS_STRING_ENABLED #if VMA_STATS_STRING_ENABLED
VmaBufferImageUsage m_BufferImageUsage; // 0 if unknown. VmaBufferImageUsage m_BufferImageUsage; // 0 if unknown.
#endif #endif
void EnsureExtraData(VmaAllocator hAllocator);
}; };
#endif // _VMA_ALLOCATION_T #endif // _VMA_ALLOCATION_T
@ -10867,6 +10876,7 @@ void VmaAllocation_T::InitBlockAllocation(
} }
void VmaAllocation_T::InitDedicatedAllocation( void VmaAllocation_T::InitDedicatedAllocation(
VmaAllocator allocator,
VmaPool hParentPool, VmaPool hParentPool,
uint32_t memoryTypeIndex, uint32_t memoryTypeIndex,
VkDeviceMemory hMemory, VkDeviceMemory hMemory,
@ -10881,16 +10891,29 @@ void VmaAllocation_T::InitDedicatedAllocation(
m_Size = size; m_Size = size;
m_MemoryTypeIndex = memoryTypeIndex; m_MemoryTypeIndex = memoryTypeIndex;
m_SuballocationType = (uint8_t)suballocationType; m_SuballocationType = (uint8_t)suballocationType;
m_DedicatedAllocation.m_ExtraData = VMA_NULL;
m_DedicatedAllocation.m_hParentPool = hParentPool;
m_DedicatedAllocation.m_hMemory = hMemory;
m_DedicatedAllocation.m_Prev = VMA_NULL;
m_DedicatedAllocation.m_Next = VMA_NULL;
if (pMappedData != VMA_NULL) if (pMappedData != VMA_NULL)
{ {
VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it.");
m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP;
EnsureExtraData(allocator);
m_DedicatedAllocation.m_ExtraData->m_pMappedData = pMappedData;
}
}
void VmaAllocation_T::Destroy(VmaAllocator allocator)
{
FreeName(allocator);
if (GetType() == ALLOCATION_TYPE_DEDICATED)
{
vma_delete(allocator, m_DedicatedAllocation.m_ExtraData);
} }
m_DedicatedAllocation.m_hParentPool = hParentPool;
m_DedicatedAllocation.m_hMemory = hMemory;
m_DedicatedAllocation.m_pMappedData = pMappedData;
m_DedicatedAllocation.m_Prev = VMA_NULL;
m_DedicatedAllocation.m_Next = VMA_NULL;
} }
void VmaAllocation_T::SetName(VmaAllocator hAllocator, const char* pName) void VmaAllocation_T::SetName(VmaAllocator hAllocator, const char* pName)
@ -10995,8 +11018,9 @@ void* VmaAllocation_T::GetMappedData() const
} }
break; break;
case ALLOCATION_TYPE_DEDICATED: case ALLOCATION_TYPE_DEDICATED:
VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0 || IsPersistentMap())); VMA_ASSERT((m_DedicatedAllocation.m_ExtraData != VMA_NULL && m_DedicatedAllocation.m_ExtraData->m_pMappedData != VMA_NULL) ==
return m_DedicatedAllocation.m_pMappedData; (m_MapCount != 0 || IsPersistentMap()));
return m_DedicatedAllocation.m_ExtraData != VMA_NULL ? m_DedicatedAllocation.m_ExtraData->m_pMappedData : VMA_NULL;
default: default:
VMA_ASSERT(0); VMA_ASSERT(0);
return VMA_NULL; return VMA_NULL;
@ -11037,12 +11061,14 @@ VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppDa
VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it.");
EnsureExtraData(hAllocator);
if (m_MapCount != 0 || IsPersistentMap()) if (m_MapCount != 0 || IsPersistentMap())
{ {
if (m_MapCount < 0xFF) if (m_MapCount < 0xFF)
{ {
VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL); VMA_ASSERT(m_DedicatedAllocation.m_ExtraData->m_pMappedData != VMA_NULL);
*ppData = m_DedicatedAllocation.m_pMappedData; *ppData = m_DedicatedAllocation.m_ExtraData->m_pMappedData;
++m_MapCount; ++m_MapCount;
return VK_SUCCESS; return VK_SUCCESS;
} }
@ -11063,7 +11089,7 @@ VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppDa
ppData); ppData);
if (result == VK_SUCCESS) if (result == VK_SUCCESS)
{ {
m_DedicatedAllocation.m_pMappedData = *ppData; m_DedicatedAllocation.m_ExtraData->m_pMappedData = *ppData;
m_MapCount = 1; m_MapCount = 1;
} }
return result; return result;
@ -11079,7 +11105,8 @@ void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
--m_MapCount; --m_MapCount;
if (m_MapCount == 0 && !IsPersistentMap()) if (m_MapCount == 0 && !IsPersistentMap())
{ {
m_DedicatedAllocation.m_pMappedData = VMA_NULL; VMA_ASSERT(m_DedicatedAllocation.m_ExtraData != VMA_NULL);
m_DedicatedAllocation.m_ExtraData->m_pMappedData = VMA_NULL;
(*hAllocator->GetVulkanFunctions().vkUnmapMemory)( (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
hAllocator->m_hDevice, hAllocator->m_hDevice,
m_DedicatedAllocation.m_hMemory); m_DedicatedAllocation.m_hMemory);
@ -11118,14 +11145,14 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
#if VMA_EXTERNAL_MEMORY_WIN32 #if VMA_EXTERNAL_MEMORY_WIN32
VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept
{ {
// Where do we get this function from?
auto pvkGetMemoryWin32HandleKHR = hAllocator->GetVulkanFunctions().vkGetMemoryWin32HandleKHR; auto pvkGetMemoryWin32HandleKHR = hAllocator->GetVulkanFunctions().vkGetMemoryWin32HandleKHR;
switch (m_Type) switch (m_Type)
{ {
case ALLOCATION_TYPE_BLOCK: case ALLOCATION_TYPE_BLOCK:
return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle);
case ALLOCATION_TYPE_DEDICATED: case ALLOCATION_TYPE_DEDICATED:
return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); EnsureExtraData(hAllocator);
return m_DedicatedAllocation.m_ExtraData->m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle);
default: default:
VMA_ASSERT(0); VMA_ASSERT(0);
return VK_ERROR_FEATURE_NOT_PRESENT; return VK_ERROR_FEATURE_NOT_PRESENT;
@ -11134,6 +11161,14 @@ VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTarget
#endif // VMA_EXTERNAL_MEMORY_WIN32 #endif // VMA_EXTERNAL_MEMORY_WIN32
#endif // VMA_STATS_STRING_ENABLED #endif // VMA_STATS_STRING_ENABLED
void VmaAllocation_T::EnsureExtraData(VmaAllocator hAllocator)
{
if (m_DedicatedAllocation.m_ExtraData == VMA_NULL)
{
m_DedicatedAllocation.m_ExtraData = vma_new(hAllocator, VmaAllocationExtraData)();
}
}
void VmaAllocation_T::FreeName(VmaAllocator hAllocator) void VmaAllocation_T::FreeName(VmaAllocator hAllocator)
{ {
if(m_pName) if(m_pName)
@ -11562,6 +11597,7 @@ void VmaBlockVector::Free(const VmaAllocation hAllocation)
} }
m_hAllocator->m_Budget.RemoveAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), hAllocation->GetSize()); m_hAllocator->m_Budget.RemoveAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), hAllocation->GetSize());
hAllocation->Destroy(m_hAllocator);
m_hAllocator->m_AllocationObjectAllocator.Free(hAllocation); m_hAllocator->m_AllocationObjectAllocator.Free(hAllocation);
} }
@ -13705,7 +13741,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
} }
*pAllocation = m_AllocationObjectAllocator.Allocate(isMappingAllowed); *pAllocation = m_AllocationObjectAllocator.Allocate(isMappingAllowed);
(*pAllocation)->InitDedicatedAllocation(pool, memTypeIndex, hMemory, suballocType, pMappedData, size); (*pAllocation)->InitDedicatedAllocation(this, pool, memTypeIndex, hMemory, suballocType, pMappedData, size);
if (isUserDataString) if (isUserDataString)
(*pAllocation)->SetName(this, (const char*)pUserData); (*pAllocation)->SetName(this, (const char*)pUserData);
else else
@ -14041,8 +14077,6 @@ void VmaAllocator_T::FreeMemory(
FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED); FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED);
} }
allocation->FreeName(this);
switch(allocation->GetType()) switch(allocation->GetType())
{ {
case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
@ -14726,6 +14760,7 @@ void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory); FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize()); m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
allocation->Destroy(this);
m_AllocationObjectAllocator.Free(allocation); m_AllocationObjectAllocator.Free(allocation);
VMA_DEBUG_LOG_FORMAT(" Freed DedicatedMemory MemoryTypeIndex=%" PRIu32, memTypeIndex); VMA_DEBUG_LOG_FORMAT(" Freed DedicatedMemory MemoryTypeIndex=%" PRIu32, memTypeIndex);
@ -16615,7 +16650,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock V
VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, 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) VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* VMA_NOT_NULL pHandle)
{ {
VMA_ASSERT(allocator && allocation); VMA_ASSERT(allocator && allocation && pHandle);
VMA_DEBUG_GLOBAL_MUTEX_LOCK; VMA_DEBUG_GLOBAL_MUTEX_LOCK;
return allocation->GetWin32Handle(allocator, hTargetProcess, pHandle); return allocation->GetWin32Handle(allocator, hTargetProcess, pHandle);
} }
@ -16753,6 +16788,7 @@ VK_EXT_memory_budget | #VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT
VK_KHR_buffer_device_address | #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT VK_KHR_buffer_device_address | #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT
VK_EXT_memory_priority | #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT VK_EXT_memory_priority | #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT
VK_AMD_device_coherent_memory | #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT VK_AMD_device_coherent_memory | #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT
VK_KHR_external_memory_win32 | #VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT
Example with fetching pointers to Vulkan functions dynamically: Example with fetching pointers to Vulkan functions dynamically:

View File

@ -34,7 +34,7 @@ foreach(SHADER ${SHADERS})
DEPENDS ${SHADER} DEPENDS ${SHADER}
) )
list(APPEND SPIRV_FILES ${SPIRV}) list(APPEND SPIRV_FILES ${SPIRV} ${SPIRV_BIN})
endforeach() endforeach()
add_custom_target(VmaSampleShaders ALL DEPENDS ${SPIRV_FILES}) add_custom_target(VmaSampleShaders ALL DEPENDS ${SPIRV_FILES})

View File

@ -8258,52 +8258,49 @@ static void TestWin32Handles()
{ {
#if VMA_EXTERNAL_MEMORY_WIN32 #if VMA_EXTERNAL_MEMORY_WIN32
wprintf(L"Test Win32 handles\n"); wprintf(L"Test Win32 handles\n");
constexpr static VkExportMemoryAllocateInfoKHR exportInfo{ constexpr static VkExportMemoryAllocateInfoKHR exportMemAllocInfo{
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
nullptr, nullptr,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
}; };
constexpr static VkExternalMemoryBufferCreateInfoKHR externalInfo{ constexpr static VkExternalMemoryBufferCreateInfoKHR externalMemBufCreateInfo{
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
nullptr, nullptr,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
}; };
VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
sampleBufCreateInfo.size = 0x1000; // Doesn't matter. bufCreateInfo.size = 0x10000;
sampleBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
sampleBufCreateInfo.pNext = &externalInfo; bufCreateInfo.pNext = &externalMemBufCreateInfo;
VmaAllocationCreateInfo sampleAllocCreateInfo = {}; VmaAllocationCreateInfo allocCreateInfo = {};
sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
sampleAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
uint32_t memTypeIndex; uint32_t memTypeIndex = UINT32_MAX;
TEST(vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, TEST(vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator,
&sampleBufCreateInfo, &sampleAllocCreateInfo, &memTypeIndex) == VK_SUCCESS); &bufCreateInfo, &allocCreateInfo, &memTypeIndex) == VK_SUCCESS);
// Check res...
// Create a pool that can have at most 2 blocks, 128 MiB each. // Create a pool that can have at most 2 blocks, 128 MiB each.
VmaPoolCreateInfo poolCreateInfo = {}; VmaPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.memoryTypeIndex = memTypeIndex; poolCreateInfo.memoryTypeIndex = memTypeIndex;
poolCreateInfo.blockSize = 128ull * 1024 * 1024; poolCreateInfo.pMemoryAllocateNext = (void*)&exportMemAllocInfo;
poolCreateInfo.maxBlockCount = 2;
poolCreateInfo.pMemoryAllocateNext = (void*)&exportInfo;
VmaPool pool = VK_NULL_HANDLE;
VmaPool pool;
TEST(vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS); TEST(vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS);
allocCreateInfo.pool = pool;
sampleAllocCreateInfo.pool = pool; for (size_t test = 0; test < 2; ++test)
{
if (test == 1)
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
VkBuffer buf; VkBuffer buf = VK_NULL_HANDLE;
VmaAllocation alloc; VmaAllocation alloc = VK_NULL_HANDLE;
VmaAllocationInfo allocInfo; TEST(vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, nullptr) == VK_SUCCESS);
TEST(vmaCreateBuffer(g_hAllocator, &sampleBufCreateInfo, &sampleAllocCreateInfo, &buf, &alloc, &allocInfo) == VK_SUCCESS); HANDLE handle = NULL;
HANDLE handle; HANDLE handle2 = NULL;
HANDLE handle2;
TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle) == VK_SUCCESS); TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle) == VK_SUCCESS);
TEST(handle != nullptr); TEST(handle != nullptr);
TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle2) == VK_SUCCESS); TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle2) == VK_SUCCESS);
@ -8313,6 +8310,7 @@ static void TestWin32Handles()
vmaDestroyBuffer(g_hAllocator, buf, alloc); vmaDestroyBuffer(g_hAllocator, buf, alloc);
TEST(CloseHandle(handle)); TEST(CloseHandle(handle));
TEST(CloseHandle(handle2)); TEST(CloseHandle(handle2));
}
vmaDestroyPool(g_hAllocator, pool); vmaDestroyPool(g_hAllocator, pool);
#endif #endif

View File

@ -96,6 +96,9 @@ include all public interface declarations. Example:
#pragma clang diagnostic ignored "-Wnullability-completeness" #pragma clang diagnostic ignored "-Wnullability-completeness"
#endif #endif
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_win32.h>
#include "vk_mem_alloc.h" #include "vk_mem_alloc.h"
#ifdef __clang__ #ifdef __clang__