Preparations for adding support for alternative algorithms in virtual blocks and tests for them
diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h
index 528480a..9201e10 100644
--- a/include/vk_mem_alloc.h
+++ b/include/vk_mem_alloc.h
@@ -8887,14 +8887,20 @@
if(!suballocations1st.empty())
{
// Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
- VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].userData != VMA_NULL);
- // Null item at the end should be just pop_back().
- VMA_VALIDATE(suballocations1st.back().userData != VMA_NULL);
+ if(!IsVirtual())
+ {
+ VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].userData != VMA_NULL);
+ // Null item at the end should be just pop_back().
+ VMA_VALIDATE(suballocations1st.back().userData != VMA_NULL);
+ }
}
if(!suballocations2nd.empty())
{
- // Null item at the end should be just pop_back().
- VMA_VALIDATE(suballocations2nd.back().userData != VMA_NULL);
+ if(!IsVirtual())
+ {
+ // Null item at the end should be just pop_back().
+ VMA_VALIDATE(suballocations2nd.back().userData != VMA_NULL);
+ }
}
VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
@@ -10555,7 +10561,7 @@
// Find more null items at the beginning of 1st vector.
while(m_1stNullItemsBeginCount < suballoc1stCount &&
- suballocations1st[m_1stNullItemsBeginCount].userData == VMA_NULL)
+ suballocations1st[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE)
{
++m_1stNullItemsBeginCount;
--m_1stNullItemsMiddleCount;
@@ -10563,7 +10569,7 @@
// Find more null items at the end of 1st vector.
while(m_1stNullItemsMiddleCount > 0 &&
- suballocations1st.back().userData == VMA_NULL)
+ suballocations1st.back().type == VMA_SUBALLOCATION_TYPE_FREE)
{
--m_1stNullItemsMiddleCount;
suballocations1st.pop_back();
@@ -10571,7 +10577,7 @@
// Find more null items at the end of 2nd vector.
while(m_2ndNullItemsCount > 0 &&
- suballocations2nd.back().userData == VMA_NULL)
+ suballocations2nd.back().type == VMA_SUBALLOCATION_TYPE_FREE)
{
--m_2ndNullItemsCount;
suballocations2nd.pop_back();
@@ -10579,7 +10585,7 @@
// Find more null items at the beginning of 2nd vector.
while(m_2ndNullItemsCount > 0 &&
- suballocations2nd[0].userData == VMA_NULL)
+ suballocations2nd[0].type == VMA_SUBALLOCATION_TYPE_FREE)
{
--m_2ndNullItemsCount;
VmaVectorRemove(suballocations2nd, 0);
@@ -10591,7 +10597,7 @@
size_t srcIndex = m_1stNullItemsBeginCount;
for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
{
- while(suballocations1st[srcIndex].userData == VMA_NULL)
+ while(suballocations1st[srcIndex].type == VMA_SUBALLOCATION_TYPE_FREE)
{
++srcIndex;
}
@@ -10624,7 +10630,7 @@
m_2ndVectorMode = SECOND_VECTOR_EMPTY;
m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
- suballocations2nd[m_1stNullItemsBeginCount].userData == VMA_NULL)
+ suballocations2nd[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE)
{
++m_1stNullItemsBeginCount;
--m_1stNullItemsMiddleCount;
diff --git a/src/Tests.cpp b/src/Tests.cpp
index db1d7e7..50b34cc 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -2817,6 +2817,144 @@
}
}
+static void TestVirtualBlocksAlgorithms()
+{
+ wprintf(L"Test virtual blocks algorithms\n");
+
+ RandomNumberGenerator rand{3454335};
+ auto calcRandomAllocSize = [&rand]() -> VkDeviceSize { return rand.Generate() % 20 + 5; };
+
+ for(size_t algorithmIndex = 0; algorithmIndex < 1/*3*/; ++algorithmIndex)
+ {
+ // Create the block
+ VmaVirtualBlockCreateInfo blockCreateInfo = {};
+ blockCreateInfo.pAllocationCallbacks = g_Allocs;
+ blockCreateInfo.size = 10'000;
+ switch(algorithmIndex)
+ {
+ case 1: blockCreateInfo.flags = VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT; break;
+ case 2: blockCreateInfo.flags = VMA_VIRTUAL_BLOCK_CREATE_BUDDY_ALGORITHM_BIT; break;
+ }
+ VmaVirtualBlock block = nullptr;
+ VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &block);
+ TEST(res == VK_SUCCESS);
+
+ struct AllocData
+ {
+ VkDeviceSize offset, size;
+ };
+ std::vector<AllocData> allocations;
+
+ // Make some allocations
+ for(size_t i = 0; i < 20; ++i)
+ {
+ VmaVirtualAllocationCreateInfo allocCreateInfo = {};
+ allocCreateInfo.size = calcRandomAllocSize();
+ allocCreateInfo.pUserData = (void*)(uintptr_t)(allocCreateInfo.size * 10);
+ if(i < 10) { }
+ else if(i < 12) allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT;
+ else if(i < 14) allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
+ else if(i < 16) allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT;
+ else if(i < 18 && algorithmIndex == 1) allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT;
+
+ AllocData alloc = {};
+ alloc.size = allocCreateInfo.size;
+ res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc.offset);
+ TEST(res == VK_SUCCESS);
+ allocations.push_back(alloc);
+ }
+
+ // Free some of the allocations
+ for(size_t i = 0; i < 5; ++i)
+ {
+ const size_t index = rand.Generate() % allocations.size();
+ vmaVirtualFree(block, allocations[index].offset);
+ allocations.erase(allocations.begin() + index);
+ }
+
+ // Allocate some more
+ for(size_t i = 0; i < 6; ++i)
+ {
+ VmaVirtualAllocationCreateInfo allocCreateInfo = {};
+ allocCreateInfo.size = calcRandomAllocSize();
+ allocCreateInfo.pUserData = (void*)(uintptr_t)(allocCreateInfo.size * 10);
+
+ AllocData alloc = {};
+ alloc.size = allocCreateInfo.size;
+ res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc.offset);
+ TEST(res == VK_SUCCESS);
+ allocations.push_back(alloc);
+ }
+
+ // Allocate some with extra alignment
+ for(size_t i = 0; i < 3; ++i)
+ {
+ VmaVirtualAllocationCreateInfo allocCreateInfo = {};
+ allocCreateInfo.size = calcRandomAllocSize();
+ allocCreateInfo.alignment = 16;
+ allocCreateInfo.pUserData = (void*)(uintptr_t)(allocCreateInfo.size * 10);
+
+ AllocData alloc = {};
+ alloc.size = allocCreateInfo.size;
+ res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc.offset);
+ TEST(res == VK_SUCCESS);
+ TEST(alloc.offset % 16 == 0);
+ allocations.push_back(alloc);
+ }
+
+ // Check if the allocations don't overlap
+ std::sort(allocations.begin(), allocations.end(), [](const AllocData& lhs, const AllocData& rhs) {
+ return lhs.offset < rhs.offset; });
+ for(size_t i = 0; i < allocations.size() - 1; ++i)
+ {
+ TEST(allocations[i+1].offset >= allocations[i].offset + allocations[i].size);
+ }
+
+ // Check pUserData
+ {
+ const AllocData& alloc = allocations.back();
+ VmaVirtualAllocationInfo allocInfo = {};
+ vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
+ TEST((uintptr_t)allocInfo.pUserData == alloc.size * 10);
+
+ vmaSetVirtualAllocationUserData(block, alloc.offset, (void*)(uintptr_t)666);
+ vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
+ TEST((uintptr_t)allocInfo.pUserData == 666);
+ }
+
+ // Calculate statistics
+ {
+ VkDeviceSize allocSizeMin = VK_WHOLE_SIZE, allocSizeMax = 0, allocSizeSum = 0;
+ std::for_each(allocations.begin(), allocations.end(), [&](const AllocData& a) {
+ allocSizeMin = std::min(allocSizeMin, a.size);
+ allocSizeMax = std::max(allocSizeMax, a.size);
+ allocSizeSum += a.size;
+ });
+
+ VmaStatInfo statInfo = {};
+ vmaCalculateVirtualBlockStats(block, &statInfo);
+ TEST(statInfo.allocationCount == allocations.size());
+ TEST(statInfo.blockCount == 1);
+ TEST(statInfo.usedBytes + statInfo.unusedBytes == blockCreateInfo.size);
+ TEST(statInfo.allocationSizeMax == allocSizeMax);
+ TEST(statInfo.allocationSizeMin == allocSizeMin);
+ TEST(statInfo.usedBytes >= allocSizeSum);
+ }
+
+ // Build JSON dump string
+ {
+ char* json = nullptr;
+ vmaBuildVirtualBlockStatsString(block, &json, VK_TRUE);
+ int I = 0; // put a breakpoint here to debug
+ vmaFreeVirtualBlockStatsString(block, json);
+ }
+
+ // Final cleanup
+ vmaClearVirtualBlock(block);
+ vmaDestroyVirtualBlock(block);
+ }
+}
+
static void TestAllocationVersusResourceSize()
{
wprintf(L"Test allocation versus resource size\n");
@@ -6696,7 +6834,7 @@
{
////////////////////////////////////////////////////////////////////////////////
// Temporarily insert custom tests here:
- TestVirtualBlocks();
+ TestVirtualBlocksAlgorithms();
return;
}