mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-05 12:20:07 +00:00
Preparations for adding support for alternative algorithms in virtual blocks and tests for them
This commit is contained in:
parent
01a0ba193a
commit
73ff8e07d1
@ -8887,14 +8887,20 @@ bool VmaBlockMetadata_Linear::Validate() const
|
|||||||
if(!suballocations1st.empty())
|
if(!suballocations1st.empty())
|
||||||
{
|
{
|
||||||
// Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
|
// Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
|
||||||
VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].userData != VMA_NULL);
|
if(!IsVirtual())
|
||||||
// Null item at the end should be just pop_back().
|
{
|
||||||
VMA_VALIDATE(suballocations1st.back().userData != VMA_NULL);
|
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())
|
if(!suballocations2nd.empty())
|
||||||
{
|
{
|
||||||
// Null item at the end should be just pop_back().
|
if(!IsVirtual())
|
||||||
VMA_VALIDATE(suballocations2nd.back().userData != VMA_NULL);
|
{
|
||||||
|
// 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());
|
VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
|
||||||
@ -10555,7 +10561,7 @@ void VmaBlockMetadata_Linear::CleanupAfterFree()
|
|||||||
|
|
||||||
// Find more null items at the beginning of 1st vector.
|
// Find more null items at the beginning of 1st vector.
|
||||||
while(m_1stNullItemsBeginCount < suballoc1stCount &&
|
while(m_1stNullItemsBeginCount < suballoc1stCount &&
|
||||||
suballocations1st[m_1stNullItemsBeginCount].userData == VMA_NULL)
|
suballocations1st[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
{
|
{
|
||||||
++m_1stNullItemsBeginCount;
|
++m_1stNullItemsBeginCount;
|
||||||
--m_1stNullItemsMiddleCount;
|
--m_1stNullItemsMiddleCount;
|
||||||
@ -10563,7 +10569,7 @@ void VmaBlockMetadata_Linear::CleanupAfterFree()
|
|||||||
|
|
||||||
// Find more null items at the end of 1st vector.
|
// Find more null items at the end of 1st vector.
|
||||||
while(m_1stNullItemsMiddleCount > 0 &&
|
while(m_1stNullItemsMiddleCount > 0 &&
|
||||||
suballocations1st.back().userData == VMA_NULL)
|
suballocations1st.back().type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
{
|
{
|
||||||
--m_1stNullItemsMiddleCount;
|
--m_1stNullItemsMiddleCount;
|
||||||
suballocations1st.pop_back();
|
suballocations1st.pop_back();
|
||||||
@ -10571,7 +10577,7 @@ void VmaBlockMetadata_Linear::CleanupAfterFree()
|
|||||||
|
|
||||||
// Find more null items at the end of 2nd vector.
|
// Find more null items at the end of 2nd vector.
|
||||||
while(m_2ndNullItemsCount > 0 &&
|
while(m_2ndNullItemsCount > 0 &&
|
||||||
suballocations2nd.back().userData == VMA_NULL)
|
suballocations2nd.back().type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
{
|
{
|
||||||
--m_2ndNullItemsCount;
|
--m_2ndNullItemsCount;
|
||||||
suballocations2nd.pop_back();
|
suballocations2nd.pop_back();
|
||||||
@ -10579,7 +10585,7 @@ void VmaBlockMetadata_Linear::CleanupAfterFree()
|
|||||||
|
|
||||||
// Find more null items at the beginning of 2nd vector.
|
// Find more null items at the beginning of 2nd vector.
|
||||||
while(m_2ndNullItemsCount > 0 &&
|
while(m_2ndNullItemsCount > 0 &&
|
||||||
suballocations2nd[0].userData == VMA_NULL)
|
suballocations2nd[0].type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
{
|
{
|
||||||
--m_2ndNullItemsCount;
|
--m_2ndNullItemsCount;
|
||||||
VmaVectorRemove(suballocations2nd, 0);
|
VmaVectorRemove(suballocations2nd, 0);
|
||||||
@ -10591,7 +10597,7 @@ void VmaBlockMetadata_Linear::CleanupAfterFree()
|
|||||||
size_t srcIndex = m_1stNullItemsBeginCount;
|
size_t srcIndex = m_1stNullItemsBeginCount;
|
||||||
for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
|
for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
|
||||||
{
|
{
|
||||||
while(suballocations1st[srcIndex].userData == VMA_NULL)
|
while(suballocations1st[srcIndex].type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
{
|
{
|
||||||
++srcIndex;
|
++srcIndex;
|
||||||
}
|
}
|
||||||
@ -10624,7 +10630,7 @@ void VmaBlockMetadata_Linear::CleanupAfterFree()
|
|||||||
m_2ndVectorMode = SECOND_VECTOR_EMPTY;
|
m_2ndVectorMode = SECOND_VECTOR_EMPTY;
|
||||||
m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
|
m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
|
||||||
while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
|
while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
|
||||||
suballocations2nd[m_1stNullItemsBeginCount].userData == VMA_NULL)
|
suballocations2nd[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
{
|
{
|
||||||
++m_1stNullItemsBeginCount;
|
++m_1stNullItemsBeginCount;
|
||||||
--m_1stNullItemsMiddleCount;
|
--m_1stNullItemsMiddleCount;
|
||||||
|
140
src/Tests.cpp
140
src/Tests.cpp
@ -2817,6 +2817,144 @@ static void TestVirtualBlocks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
static void TestAllocationVersusResourceSize()
|
||||||
{
|
{
|
||||||
wprintf(L"Test allocation versus resource size\n");
|
wprintf(L"Test allocation versus resource size\n");
|
||||||
@ -6696,7 +6834,7 @@ void Test()
|
|||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Temporarily insert custom tests here:
|
// Temporarily insert custom tests here:
|
||||||
TestVirtualBlocks();
|
TestVirtualBlocksAlgorithms();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user