mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2024-11-26 16:34:35 +00:00
Added support for lost allocations in ring buffer.
Fixed some more bugs.
This commit is contained in:
parent
fd11d759dd
commit
8cfe05fad9
102
src/Tests.cpp
102
src/Tests.cpp
@ -101,6 +101,8 @@ struct PoolTestResult
|
|||||||
|
|
||||||
static const uint32_t IMAGE_BYTES_PER_PIXEL = 1;
|
static const uint32_t IMAGE_BYTES_PER_PIXEL = 1;
|
||||||
|
|
||||||
|
static uint32_t g_FrameIndex = 0;
|
||||||
|
|
||||||
struct BufferInfo
|
struct BufferInfo
|
||||||
{
|
{
|
||||||
VkBuffer Buffer = VK_NULL_HANDLE;
|
VkBuffer Buffer = VK_NULL_HANDLE;
|
||||||
@ -1701,6 +1703,95 @@ static void TestLinearAllocator()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test ring buffer with lost allocations.
|
||||||
|
{
|
||||||
|
// Allocate number of buffers until pool is full.
|
||||||
|
// Notice CAN_BECOME_LOST flag and call to vmaSetCurrentFrameIndex.
|
||||||
|
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT;
|
||||||
|
res = VK_SUCCESS;
|
||||||
|
for(size_t i = 0; res == VK_SUCCESS; ++i)
|
||||||
|
{
|
||||||
|
vmaSetCurrentFrameIndex(g_hAllocator, ++g_FrameIndex);
|
||||||
|
|
||||||
|
bufCreateInfo.size = bufSizeMin + rand.Generate() % (bufSizeMax - bufSizeMin);
|
||||||
|
|
||||||
|
BufferInfo newBufInfo;
|
||||||
|
res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo,
|
||||||
|
&newBufInfo.Buffer, &newBufInfo.Allocation, &allocInfo);
|
||||||
|
if(res == VK_SUCCESS)
|
||||||
|
bufInfo.push_back(newBufInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free first half of it.
|
||||||
|
{
|
||||||
|
const size_t buffersToDelete = bufInfo.size() / 2;
|
||||||
|
for(size_t i = 0; i < buffersToDelete; ++i)
|
||||||
|
{
|
||||||
|
vmaDestroyBuffer(g_hAllocator, bufInfo[i].Buffer, bufInfo[i].Allocation);
|
||||||
|
}
|
||||||
|
bufInfo.erase(bufInfo.begin(), bufInfo.begin() + buffersToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate number of buffers until pool is full again.
|
||||||
|
// This way we make sure ring buffers wraps around.
|
||||||
|
res = VK_SUCCESS;
|
||||||
|
for(size_t i = 0; res == VK_SUCCESS; ++i)
|
||||||
|
{
|
||||||
|
vmaSetCurrentFrameIndex(g_hAllocator, ++g_FrameIndex);
|
||||||
|
|
||||||
|
bufCreateInfo.size = bufSizeMin + rand.Generate() % (bufSizeMax - bufSizeMin);
|
||||||
|
|
||||||
|
BufferInfo newBufInfo;
|
||||||
|
res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo,
|
||||||
|
&newBufInfo.Buffer, &newBufInfo.Allocation, &allocInfo);
|
||||||
|
if(res == VK_SUCCESS)
|
||||||
|
bufInfo.push_back(newBufInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize firstNewOffset;
|
||||||
|
{
|
||||||
|
vmaSetCurrentFrameIndex(g_hAllocator, ++g_FrameIndex);
|
||||||
|
|
||||||
|
// Allocate a large buffer with CAN_MAKE_OTHER_LOST.
|
||||||
|
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;
|
||||||
|
bufCreateInfo.size = bufSizeMax;
|
||||||
|
|
||||||
|
BufferInfo newBufInfo;
|
||||||
|
res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo,
|
||||||
|
&newBufInfo.Buffer, &newBufInfo.Allocation, &allocInfo);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
bufInfo.push_back(newBufInfo);
|
||||||
|
firstNewOffset = allocInfo.offset;
|
||||||
|
|
||||||
|
// Make sure at least one buffer from the beginning became lost.
|
||||||
|
vmaGetAllocationInfo(g_hAllocator, bufInfo[0].Allocation, &allocInfo);
|
||||||
|
assert(allocInfo.deviceMemory == VK_NULL_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate more buffers that CAN_MAKE_OTHER_LOST until we wrap-around with this.
|
||||||
|
size_t newCount = 1;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
vmaSetCurrentFrameIndex(g_hAllocator, ++g_FrameIndex);
|
||||||
|
|
||||||
|
bufCreateInfo.size = bufSizeMin + rand.Generate() % (bufSizeMax - bufSizeMin);
|
||||||
|
|
||||||
|
BufferInfo newBufInfo;
|
||||||
|
res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo,
|
||||||
|
&newBufInfo.Buffer, &newBufInfo.Allocation, &allocInfo);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
bufInfo.push_back(newBufInfo);
|
||||||
|
++newCount;
|
||||||
|
if(allocInfo.offset < firstNewOffset)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy all the buffers in forward order.
|
||||||
|
for(size_t i = 0; i < bufInfo.size(); ++i)
|
||||||
|
vmaDestroyBuffer(g_hAllocator, bufInfo[i].Buffer, bufInfo[i].Allocation);
|
||||||
|
bufInfo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
vmaDestroyPool(g_hAllocator, pool);
|
vmaDestroyPool(g_hAllocator, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3541,10 +3632,12 @@ void Test()
|
|||||||
{
|
{
|
||||||
wprintf(L"TESTING:\n");
|
wprintf(L"TESTING:\n");
|
||||||
|
|
||||||
// TEMP tests
|
// TODO delete
|
||||||
TestLinearAllocator();
|
{
|
||||||
ManuallyTestLinearAllocator();
|
TestLinearAllocator();
|
||||||
return;
|
ManuallyTestLinearAllocator();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// # Simple tests
|
// # Simple tests
|
||||||
|
|
||||||
@ -3561,6 +3654,7 @@ return;
|
|||||||
TestMapping();
|
TestMapping();
|
||||||
TestMappingMultithreaded();
|
TestMappingMultithreaded();
|
||||||
TestLinearAllocator();
|
TestLinearAllocator();
|
||||||
|
ManuallyTestLinearAllocator();
|
||||||
TestDefragmentationSimple();
|
TestDefragmentationSimple();
|
||||||
TestDefragmentationFull();
|
TestDefragmentationFull();
|
||||||
|
|
||||||
|
@ -8102,6 +8102,7 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
VMA_ASSERT(pAllocationRequest != VMA_NULL);
|
VMA_ASSERT(pAllocationRequest != VMA_NULL);
|
||||||
VMA_HEAVY_ASSERT(Validate());
|
VMA_HEAVY_ASSERT(Validate());
|
||||||
|
|
||||||
|
const VkDeviceSize size = GetSize();
|
||||||
SuballocationVectorType& suballocations1st = AccessSuballocations1st();
|
SuballocationVectorType& suballocations1st = AccessSuballocations1st();
|
||||||
SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
|
SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
|
||||||
|
|
||||||
@ -8114,11 +8115,11 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to allocate before 2nd.back(), or end of block if 2nd.empty().
|
// Try to allocate before 2nd.back(), or end of block if 2nd.empty().
|
||||||
if(allocSize > GetSize())
|
if(allocSize > size)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
VkDeviceSize resultBaseOffset = GetSize() - allocSize;
|
VkDeviceSize resultBaseOffset = size - allocSize;
|
||||||
if(!suballocations2nd.empty())
|
if(!suballocations2nd.empty())
|
||||||
{
|
{
|
||||||
const VmaSuballocation& lastSuballoc = suballocations2nd.back();
|
const VmaSuballocation& lastSuballoc = suballocations2nd.back();
|
||||||
@ -8208,11 +8209,12 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else // !upperAddress
|
||||||
{
|
{
|
||||||
if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
|
if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
|
||||||
{
|
{
|
||||||
// Try to allocate at the end of 1st vector.
|
// Try to allocate at the end of 1st vector.
|
||||||
|
|
||||||
VkDeviceSize resultBaseOffset = 0;
|
VkDeviceSize resultBaseOffset = 0;
|
||||||
if(!suballocations1st.empty())
|
if(!suballocations1st.empty())
|
||||||
{
|
{
|
||||||
@ -8259,7 +8261,7 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
|
const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
|
||||||
suballocations2nd.back().offset : GetSize();
|
suballocations2nd.back().offset : size;
|
||||||
|
|
||||||
// There is enough free space at the end after alignment.
|
// There is enough free space at the end after alignment.
|
||||||
if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd)
|
if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd)
|
||||||
@ -8300,6 +8302,8 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
// beginning of 1st vector as the end of free space.
|
// beginning of 1st vector as the end of free space.
|
||||||
if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
|
if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
|
||||||
{
|
{
|
||||||
|
VMA_ASSERT(!suballocations1st.empty());
|
||||||
|
|
||||||
VkDeviceSize resultBaseOffset = 0;
|
VkDeviceSize resultBaseOffset = 0;
|
||||||
if(!suballocations2nd.empty())
|
if(!suballocations2nd.empty())
|
||||||
{
|
{
|
||||||
@ -8345,15 +8349,81 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pAllocationRequest->itemsToMakeLostCount = 0;
|
||||||
|
pAllocationRequest->sumItemSize = 0;
|
||||||
|
size_t index1st = m_1stNullItemsBeginCount;
|
||||||
|
|
||||||
|
if(canMakeOtherLost)
|
||||||
|
{
|
||||||
|
while(index1st < suballocations1st.size() &&
|
||||||
|
resultOffset + allocSize + VMA_DEBUG_MARGIN > suballocations1st[index1st].offset)
|
||||||
|
{
|
||||||
|
// Next colliding allocation at the beginning of 1st vector found. Try to make it lost.
|
||||||
|
const VmaSuballocation& suballoc = suballocations1st[index1st];
|
||||||
|
if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
|
{
|
||||||
|
// No problem.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
|
||||||
|
if(suballoc.hAllocation->CanBecomeLost() &&
|
||||||
|
suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
|
||||||
|
{
|
||||||
|
++pAllocationRequest->itemsToMakeLostCount;
|
||||||
|
pAllocationRequest->sumItemSize += suballoc.size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++index1st;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check next suballocations for BufferImageGranularity conflicts.
|
||||||
|
// If conflict exists, we must mark more allocations lost or fail.
|
||||||
|
if(bufferImageGranularity > 1)
|
||||||
|
{
|
||||||
|
while(index1st < suballocations1st.size())
|
||||||
|
{
|
||||||
|
const VmaSuballocation& suballoc = suballocations1st[index1st];
|
||||||
|
if(VmaBlocksOnSamePage(resultOffset, allocSize, suballoc.offset, bufferImageGranularity))
|
||||||
|
{
|
||||||
|
if(suballoc.hAllocation != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
// Not checking actual VmaIsBufferImageGranularityConflict(allocType, suballoc.type).
|
||||||
|
if(suballoc.hAllocation->CanBecomeLost() &&
|
||||||
|
suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
|
||||||
|
{
|
||||||
|
++pAllocationRequest->itemsToMakeLostCount;
|
||||||
|
pAllocationRequest->sumItemSize += suballoc.size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Already on next page.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++index1st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// There is enough free space at the end after alignment.
|
// There is enough free space at the end after alignment.
|
||||||
const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
|
if(index1st == suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN < size ||
|
||||||
if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpace2ndTo1stEnd)
|
index1st < suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= suballocations1st[index1st].offset)
|
||||||
{
|
{
|
||||||
// Check next suballocations for BufferImageGranularity conflicts.
|
// Check next suballocations for BufferImageGranularity conflicts.
|
||||||
// If conflict exists, allocation cannot be made here.
|
// If conflict exists, allocation cannot be made here.
|
||||||
if(bufferImageGranularity > 1)
|
if(bufferImageGranularity > 1)
|
||||||
{
|
{
|
||||||
for(size_t nextSuballocIndex = m_1stNullItemsBeginCount;
|
for(size_t nextSuballocIndex = index1st;
|
||||||
nextSuballocIndex < suballocations1st.size();
|
nextSuballocIndex < suballocations1st.size();
|
||||||
nextSuballocIndex++)
|
nextSuballocIndex++)
|
||||||
{
|
{
|
||||||
@ -8375,10 +8445,11 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest(
|
|||||||
|
|
||||||
// All tests passed: Success.
|
// All tests passed: Success.
|
||||||
pAllocationRequest->offset = resultOffset;
|
pAllocationRequest->offset = resultOffset;
|
||||||
pAllocationRequest->sumFreeSize = freeSpace2ndTo1stEnd - resultBaseOffset;
|
pAllocationRequest->sumFreeSize =
|
||||||
pAllocationRequest->sumItemSize = 0;
|
(index1st < suballocations1st.size() ? suballocations1st[index1st].offset : size)
|
||||||
|
- resultBaseOffset
|
||||||
|
- pAllocationRequest->sumItemSize;
|
||||||
// pAllocationRequest->item unused.
|
// pAllocationRequest->item unused.
|
||||||
pAllocationRequest->itemsToMakeLostCount = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8392,8 +8463,43 @@ bool VmaBlockMetadata_Linear::MakeRequestedAllocationsLost(
|
|||||||
uint32_t frameInUseCount,
|
uint32_t frameInUseCount,
|
||||||
VmaAllocationRequest* pAllocationRequest)
|
VmaAllocationRequest* pAllocationRequest)
|
||||||
{
|
{
|
||||||
VMA_ASSERT(0 && "TODO");
|
if(pAllocationRequest->itemsToMakeLostCount == 0)
|
||||||
return false;
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VMA_ASSERT(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER);
|
||||||
|
|
||||||
|
SuballocationVectorType& suballocations1st = AccessSuballocations1st();
|
||||||
|
size_t index1st = m_1stNullItemsBeginCount;
|
||||||
|
size_t madeLostCount = 0;
|
||||||
|
while(madeLostCount < pAllocationRequest->itemsToMakeLostCount)
|
||||||
|
{
|
||||||
|
VMA_ASSERT(index1st < suballocations1st.size());
|
||||||
|
VmaSuballocation& suballoc = suballocations1st[index1st];
|
||||||
|
if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
|
{
|
||||||
|
VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
|
||||||
|
VMA_ASSERT(suballoc.hAllocation->CanBecomeLost());
|
||||||
|
if(suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
|
||||||
|
{
|
||||||
|
suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
|
||||||
|
suballoc.hAllocation = VK_NULL_HANDLE;
|
||||||
|
++m_1stNullItemsMiddleCount;
|
||||||
|
++madeLostCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++index1st;
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanupAfterFree();
|
||||||
|
//VMA_HEAVY_ASSERT(Validate()); // Already called by ClanupAfterFree().
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
|
uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
|
||||||
|
Loading…
Reference in New Issue
Block a user