Fix VmaAllocator_T::AllocateMemory for case when VMA_ALLOCATION_CREATE_MAPPED_BIT is used with custom memory pool created in memory type that is not VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
Also add test for it - function TestDeviceLocalMapped.
diff --git a/src/Tests.cpp b/src/Tests.cpp
index 4d6ed51..8e9b66b 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -4107,6 +4107,51 @@
}
}
+// Test CREATE_MAPPED with required DEVICE_LOCAL. There was a bug with it.
+static void TestDeviceLocalMapped()
+{
+ VkResult res;
+
+ for(uint32_t testIndex = 0; testIndex < 3; ++testIndex)
+ {
+ VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
+ bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ bufCreateInfo.size = 4096;
+
+ VmaPool pool = VK_NULL_HANDLE;
+ VmaAllocationCreateInfo allocCreateInfo = {};
+ allocCreateInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
+ if(testIndex == 2)
+ {
+ VmaPoolCreateInfo poolCreateInfo = {};
+ res = vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &poolCreateInfo.memoryTypeIndex);
+ TEST(res == VK_SUCCESS);
+ res = vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool);
+ TEST(res == VK_SUCCESS);
+ allocCreateInfo.pool = pool;
+ }
+ else if(testIndex == 1)
+ {
+ allocCreateInfo.flags |= VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;
+ }
+
+ VkBuffer buf = VK_NULL_HANDLE;
+ VmaAllocation alloc = VK_NULL_HANDLE;
+ VmaAllocationInfo allocInfo = {};
+ res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
+ TEST(res == VK_SUCCESS && alloc);
+
+ VkMemoryPropertyFlags memTypeFlags = 0;
+ vmaGetMemoryTypeProperties(g_hAllocator, allocInfo.memoryType, &memTypeFlags);
+ const bool shouldBeMapped = (memTypeFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
+ TEST((allocInfo.pMappedData != nullptr) == shouldBeMapped);
+
+ vmaDestroyBuffer(g_hAllocator, buf, alloc);
+ vmaDestroyPool(g_hAllocator, pool);
+ }
+}
+
static void TestMappingMultithreaded()
{
wprintf(L"Testing mapping multithreaded...\n");
@@ -5206,6 +5251,7 @@
TestAllocationsInitialization();
#endif
TestMapping();
+ TestDeviceLocalMapped();
TestMappingMultithreaded();
TestLinearAllocator();
ManuallyTestLinearAllocator();
diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h
index 66b5c07..204f002 100644
--- a/src/vk_mem_alloc.h
+++ b/src/vk_mem_alloc.h
@@ -14812,11 +14812,20 @@
const VkDeviceSize alignmentForPool = VMA_MAX(
vkMemReq.alignment,
GetMemoryTypeMinAlignment(createInfo.pool->m_BlockVector.GetMemoryTypeIndex()));
+
+ VmaAllocationCreateInfo createInfoForPool = createInfo;
+ // If memory type is not HOST_VISIBLE, disable MAPPED.
+ if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
+ (m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
+ {
+ createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
+ }
+
return createInfo.pool->m_BlockVector.Allocate(
m_CurrentFrameIndex.load(),
vkMemReq.size,
alignmentForPool,
- createInfo,
+ createInfoForPool,
suballocType,
allocationCount,
pAllocations);