mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-05 12:20:07 +00:00
Changed behavior of VMA_DEBUG_MARGIN macro - it now adds margin also before first and after last allocation in a block. Improved validation of VMA_DEBUG_MARGIN. Added test for it - function TestDebugMargin().
This commit is contained in:
parent
82c3f33547
commit
73b1665ea4
@ -1322,6 +1322,57 @@ void TestHeapSizeLimit()
|
|||||||
vmaDestroyAllocator(hAllocator);
|
vmaDestroyAllocator(hAllocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TestDebugMargin()
|
||||||
|
{
|
||||||
|
if(VMA_DEBUG_MARGIN == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
|
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||||
|
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||||
|
|
||||||
|
// Create few buffers of different size.
|
||||||
|
const size_t BUF_COUNT = 10;
|
||||||
|
BufferInfo buffers[BUF_COUNT];
|
||||||
|
VmaAllocationInfo allocInfo[BUF_COUNT];
|
||||||
|
for(size_t i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
bufInfo.size = (VkDeviceSize)(i + 1) * 64;
|
||||||
|
|
||||||
|
VkResult res = vmaCreateBuffer(g_hAllocator, &bufInfo, &allocCreateInfo, &buffers[i].Buffer, &buffers[i].Allocation, &allocInfo[i]);
|
||||||
|
assert(res == VK_SUCCESS);
|
||||||
|
// Margin is preserved also at the beginning of a block.
|
||||||
|
assert(allocInfo[i].offset >= VMA_DEBUG_MARGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if their offsets preserve margin between them.
|
||||||
|
std::sort(allocInfo, allocInfo + BUF_COUNT, [](const VmaAllocationInfo& lhs, const VmaAllocationInfo& rhs) -> bool
|
||||||
|
{
|
||||||
|
if(lhs.deviceMemory != rhs.deviceMemory)
|
||||||
|
{
|
||||||
|
return lhs.deviceMemory < rhs.deviceMemory;
|
||||||
|
}
|
||||||
|
return lhs.offset < rhs.offset;
|
||||||
|
});
|
||||||
|
for(size_t i = 1; i < BUF_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if(allocInfo[i].deviceMemory == allocInfo[i - 1].deviceMemory)
|
||||||
|
{
|
||||||
|
assert(allocInfo[i].offset >= allocInfo[i - 1].offset + VMA_DEBUG_MARGIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy all buffers.
|
||||||
|
for(size_t i = BUF_COUNT; i--; )
|
||||||
|
{
|
||||||
|
vmaDestroyBuffer(g_hAllocator, buffers[i].Buffer, buffers[i].Allocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void TestPool_SameSize()
|
static void TestPool_SameSize()
|
||||||
{
|
{
|
||||||
const VkDeviceSize BUF_SIZE = 1024 * 1024;
|
const VkDeviceSize BUF_SIZE = 1024 * 1024;
|
||||||
@ -2956,8 +3007,15 @@ void Test()
|
|||||||
// # Simple tests
|
// # Simple tests
|
||||||
|
|
||||||
TestBasics();
|
TestBasics();
|
||||||
TestPool_SameSize();
|
if(VMA_DEBUG_MARGIN)
|
||||||
TestHeapSizeLimit();
|
{
|
||||||
|
TestDebugMargin();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TestPool_SameSize();
|
||||||
|
TestHeapSizeLimit();
|
||||||
|
}
|
||||||
TestMapping();
|
TestMapping();
|
||||||
TestMappingMultithreaded();
|
TestMappingMultithreaded();
|
||||||
TestDefragmentationSimple();
|
TestDefragmentationSimple();
|
||||||
|
@ -2447,7 +2447,7 @@ If providing your own implementation, you need to implement a subset of std::ato
|
|||||||
|
|
||||||
#ifndef VMA_DEBUG_MARGIN
|
#ifndef VMA_DEBUG_MARGIN
|
||||||
/**
|
/**
|
||||||
Minimum margin between suballocations, in bytes.
|
Minimum margin before and after every allocation, in bytes.
|
||||||
Set nonzero for debugging purposes only.
|
Set nonzero for debugging purposes only.
|
||||||
*/
|
*/
|
||||||
#define VMA_DEBUG_MARGIN (0)
|
#define VMA_DEBUG_MARGIN (0)
|
||||||
@ -4081,9 +4081,6 @@ public:
|
|||||||
void PrintDetailedMap(class VmaJsonWriter& json) const;
|
void PrintDetailedMap(class VmaJsonWriter& json) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Creates trivial request for case when block is empty.
|
|
||||||
void CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest);
|
|
||||||
|
|
||||||
// Tries to find a place for suballocation with given parameters inside this block.
|
// Tries to find a place for suballocation with given parameters inside this block.
|
||||||
// If succeeded, fills pAllocationRequest and returns true.
|
// If succeeded, fills pAllocationRequest and returns true.
|
||||||
// If failed, returns false.
|
// If failed, returns false.
|
||||||
@ -5486,7 +5483,7 @@ bool VmaBlockMetadata::Validate() const
|
|||||||
// Expected number of free suballocations that should be registered in
|
// Expected number of free suballocations that should be registered in
|
||||||
// m_FreeSuballocationsBySize calculated from traversing their list.
|
// m_FreeSuballocationsBySize calculated from traversing their list.
|
||||||
size_t freeSuballocationsToRegister = 0;
|
size_t freeSuballocationsToRegister = 0;
|
||||||
// True if previous visisted suballocation was free.
|
// True if previous visited suballocation was free.
|
||||||
bool prevFree = false;
|
bool prevFree = false;
|
||||||
|
|
||||||
for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
|
for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
|
||||||
@ -5521,6 +5518,12 @@ bool VmaBlockMetadata::Validate() const
|
|||||||
{
|
{
|
||||||
++freeSuballocationsToRegister;
|
++freeSuballocationsToRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Margin required between allocations - every free space must be at least that large.
|
||||||
|
if(subAlloc.size < VMA_DEBUG_MARGIN)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -5532,6 +5535,12 @@ bool VmaBlockMetadata::Validate() const
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Margin required between allocations - previous allocation must be free.
|
||||||
|
if(VMA_DEBUG_MARGIN > 0 && !prevFree)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calculatedOffset += subAlloc.size;
|
calculatedOffset += subAlloc.size;
|
||||||
@ -5700,16 +5709,6 @@ How many suitable free suballocations to analyze before choosing best one.
|
|||||||
*/
|
*/
|
||||||
//static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8;
|
//static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8;
|
||||||
|
|
||||||
void VmaBlockMetadata::CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest)
|
|
||||||
{
|
|
||||||
VMA_ASSERT(IsEmpty());
|
|
||||||
pAllocationRequest->offset = 0;
|
|
||||||
pAllocationRequest->sumFreeSize = m_SumFreeSize;
|
|
||||||
pAllocationRequest->sumItemSize = 0;
|
|
||||||
pAllocationRequest->item = m_Suballocations.begin();
|
|
||||||
pAllocationRequest->itemsToMakeLostCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VmaBlockMetadata::CreateAllocationRequest(
|
bool VmaBlockMetadata::CreateAllocationRequest(
|
||||||
uint32_t currentFrameIndex,
|
uint32_t currentFrameIndex,
|
||||||
uint32_t frameInUseCount,
|
uint32_t frameInUseCount,
|
||||||
@ -5726,7 +5725,7 @@ bool VmaBlockMetadata::CreateAllocationRequest(
|
|||||||
VMA_HEAVY_ASSERT(Validate());
|
VMA_HEAVY_ASSERT(Validate());
|
||||||
|
|
||||||
// There is not enough total free space in this block to fullfill the request: Early return.
|
// There is not enough total free space in this block to fullfill the request: Early return.
|
||||||
if(canMakeOtherLost == false && m_SumFreeSize < allocSize)
|
if(canMakeOtherLost == false && m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5737,11 +5736,11 @@ bool VmaBlockMetadata::CreateAllocationRequest(
|
|||||||
{
|
{
|
||||||
if(VMA_BEST_FIT)
|
if(VMA_BEST_FIT)
|
||||||
{
|
{
|
||||||
// Find first free suballocation with size not less than allocSize.
|
// Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN.
|
||||||
VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
|
VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
|
||||||
m_FreeSuballocationsBySize.data(),
|
m_FreeSuballocationsBySize.data(),
|
||||||
m_FreeSuballocationsBySize.data() + freeSuballocCount,
|
m_FreeSuballocationsBySize.data() + freeSuballocCount,
|
||||||
allocSize,
|
allocSize + 2 * VMA_DEBUG_MARGIN,
|
||||||
VmaSuballocationItemSizeLess());
|
VmaSuballocationItemSizeLess());
|
||||||
size_t index = it - m_FreeSuballocationsBySize.data();
|
size_t index = it - m_FreeSuballocationsBySize.data();
|
||||||
for(; index < freeSuballocCount; ++index)
|
for(; index < freeSuballocCount; ++index)
|
||||||
@ -6067,7 +6066,7 @@ bool VmaBlockMetadata::CheckAllocation(
|
|||||||
*pOffset = suballocItem->offset;
|
*pOffset = suballocItem->offset;
|
||||||
|
|
||||||
// Apply VMA_DEBUG_MARGIN at the beginning.
|
// Apply VMA_DEBUG_MARGIN at the beginning.
|
||||||
if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin())
|
if(VMA_DEBUG_MARGIN > 0)
|
||||||
{
|
{
|
||||||
*pOffset += VMA_DEBUG_MARGIN;
|
*pOffset += VMA_DEBUG_MARGIN;
|
||||||
}
|
}
|
||||||
@ -6113,11 +6112,8 @@ bool VmaBlockMetadata::CheckAllocation(
|
|||||||
// Calculate padding at the beginning based on current offset.
|
// Calculate padding at the beginning based on current offset.
|
||||||
const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
|
const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
|
||||||
|
|
||||||
// Calculate required margin at the end if this is not last suballocation.
|
// Calculate required margin at the end.
|
||||||
VmaSuballocationList::const_iterator next = suballocItem;
|
const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
|
||||||
++next;
|
|
||||||
const VkDeviceSize requiredEndMargin =
|
|
||||||
(next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
|
|
||||||
|
|
||||||
const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
|
const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
|
||||||
// Another early return check.
|
// Another early return check.
|
||||||
@ -6213,7 +6209,7 @@ bool VmaBlockMetadata::CheckAllocation(
|
|||||||
*pOffset = suballoc.offset;
|
*pOffset = suballoc.offset;
|
||||||
|
|
||||||
// Apply VMA_DEBUG_MARGIN at the beginning.
|
// Apply VMA_DEBUG_MARGIN at the beginning.
|
||||||
if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin())
|
if(VMA_DEBUG_MARGIN > 0)
|
||||||
{
|
{
|
||||||
*pOffset += VMA_DEBUG_MARGIN;
|
*pOffset += VMA_DEBUG_MARGIN;
|
||||||
}
|
}
|
||||||
@ -6252,11 +6248,8 @@ bool VmaBlockMetadata::CheckAllocation(
|
|||||||
// Calculate padding at the beginning based on current offset.
|
// Calculate padding at the beginning based on current offset.
|
||||||
const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
|
const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
|
||||||
|
|
||||||
// Calculate required margin at the end if this is not last suballocation.
|
// Calculate required margin at the end.
|
||||||
VmaSuballocationList::const_iterator next = suballocItem;
|
const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
|
||||||
++next;
|
|
||||||
const VkDeviceSize requiredEndMargin =
|
|
||||||
(next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
|
|
||||||
|
|
||||||
// Fail if requested size plus margin before and after is bigger than size of this suballocation.
|
// Fail if requested size plus margin before and after is bigger than size of this suballocation.
|
||||||
if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
|
if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
|
||||||
@ -6695,7 +6688,7 @@ VkResult VmaBlockVector::Allocate(
|
|||||||
VmaAllocation* pAllocation)
|
VmaAllocation* pAllocation)
|
||||||
{
|
{
|
||||||
// Early reject: requested allocation size is larger that maximum block size for this block vector.
|
// Early reject: requested allocation size is larger that maximum block size for this block vector.
|
||||||
if(size > m_PreferredBlockSize)
|
if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize)
|
||||||
{
|
{
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
}
|
}
|
||||||
@ -6828,22 +6821,37 @@ VkResult VmaBlockVector::Allocate(
|
|||||||
|
|
||||||
// Allocate from pBlock. Because it is empty, dstAllocRequest can be trivially filled.
|
// Allocate from pBlock. Because it is empty, dstAllocRequest can be trivially filled.
|
||||||
VmaAllocationRequest allocRequest;
|
VmaAllocationRequest allocRequest;
|
||||||
pBlock->m_Metadata.CreateFirstAllocationRequest(&allocRequest);
|
if(pBlock->m_Metadata.CreateAllocationRequest(
|
||||||
*pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
|
currentFrameIndex,
|
||||||
pBlock->m_Metadata.Alloc(allocRequest, suballocType, size, *pAllocation);
|
m_FrameInUseCount,
|
||||||
(*pAllocation)->InitBlockAllocation(
|
m_BufferImageGranularity,
|
||||||
hCurrentPool,
|
|
||||||
pBlock,
|
|
||||||
allocRequest.offset,
|
|
||||||
alignment,
|
|
||||||
size,
|
size,
|
||||||
|
alignment,
|
||||||
suballocType,
|
suballocType,
|
||||||
mapped,
|
false, // canMakeOtherLost
|
||||||
(createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
|
&allocRequest))
|
||||||
VMA_HEAVY_ASSERT(pBlock->Validate());
|
{
|
||||||
VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize);
|
*pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
|
||||||
(*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
|
pBlock->m_Metadata.Alloc(allocRequest, suballocType, size, *pAllocation);
|
||||||
return VK_SUCCESS;
|
(*pAllocation)->InitBlockAllocation(
|
||||||
|
hCurrentPool,
|
||||||
|
pBlock,
|
||||||
|
allocRequest.offset,
|
||||||
|
alignment,
|
||||||
|
size,
|
||||||
|
suballocType,
|
||||||
|
mapped,
|
||||||
|
(createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
|
||||||
|
VMA_HEAVY_ASSERT(pBlock->Validate());
|
||||||
|
VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize);
|
||||||
|
(*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Allocation from empty block failed, possibly due to VMA_DEBUG_MARGIN or alignment.
|
||||||
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user