Added function vmaResizeAllocation.
Added tests: function TestResize. Bumped CSV recording file format version to 1.4.
This commit is contained in:
parent
1146b45c63
commit
b0c363693f
11 changed files with 530 additions and 17 deletions
|
@ -2374,6 +2374,31 @@ void vmaFreeMemory(
|
|||
VmaAllocator allocator,
|
||||
VmaAllocation allocation);
|
||||
|
||||
/** \brief Tries to resize an allocation in place, if there is enough free memory after it.
|
||||
|
||||
Tries to change allocation's size without moving or reallocating it.
|
||||
You can both shrink and grow allocation size.
|
||||
When growing, it succeeds only when the allocation belongs to a memory block with enough
|
||||
free space after it.
|
||||
|
||||
Returns `VK_SUCCESS` if allocation's size has been successfully changed.
|
||||
Returns `VK_ERROR_OUT_OF_POOL_MEMORY` if allocation's size could not be changed.
|
||||
|
||||
After successful call to this function, VmaAllocationInfo::size of this allocation changes.
|
||||
All other parameters stay the same: memory pool and type, alignment, offset, mapped pointer.
|
||||
|
||||
- Calling this function on allocation that is in lost state fails with result `VK_ERROR_VALIDATION_FAILED_EXT`.
|
||||
- Calling this function with `newSize` same as current allocation size does nothing and returns `VK_SUCCESS`.
|
||||
- Resizing dedicated allocations, as well as allocations created in pools that use linear
|
||||
or buddy algorithm, is not supported.
|
||||
The function returns `VK_ERROR_FEATURE_NOT_PRESENT` in such cases.
|
||||
Support may be added in the future.
|
||||
*/
|
||||
VkResult vmaResizeAllocation(
|
||||
VmaAllocator allocator,
|
||||
VmaAllocation allocation,
|
||||
VkDeviceSize newSize);
|
||||
|
||||
/** \brief Returns current information about specified allocation and atomically marks it as used in current frame.
|
||||
|
||||
Current paramters of given allocation are returned in `pAllocationInfo`.
|
||||
|
@ -4504,7 +4529,9 @@ public:
|
|||
void ChangeBlockAllocation(
|
||||
VmaAllocator hAllocator,
|
||||
VmaDeviceMemoryBlock* block,
|
||||
VkDeviceSize offset);
|
||||
VkDeviceSize offset);
|
||||
|
||||
void ChangeSize(VkDeviceSize newSize);
|
||||
|
||||
// pMappedData not null means allocation is created with MAPPED flag.
|
||||
void InitDedicatedAllocation(
|
||||
|
@ -4766,6 +4793,9 @@ public:
|
|||
virtual void Free(const VmaAllocation allocation) = 0;
|
||||
virtual void FreeAtOffset(VkDeviceSize offset) = 0;
|
||||
|
||||
// Tries to resize (grow or shrink) space for given allocation, in place.
|
||||
virtual bool ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize) { return false; }
|
||||
|
||||
protected:
|
||||
const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
|
||||
|
||||
|
@ -4845,6 +4875,8 @@ public:
|
|||
virtual void Free(const VmaAllocation allocation);
|
||||
virtual void FreeAtOffset(VkDeviceSize offset);
|
||||
|
||||
virtual bool ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize);
|
||||
|
||||
private:
|
||||
uint32_t m_FreeCount;
|
||||
VkDeviceSize m_SumFreeSize;
|
||||
|
@ -5597,6 +5629,10 @@ public:
|
|||
VmaAllocation allocation);
|
||||
void RecordFreeMemory(uint32_t frameIndex,
|
||||
VmaAllocation allocation);
|
||||
void RecordResizeAllocation(
|
||||
uint32_t frameIndex,
|
||||
VmaAllocation allocation,
|
||||
VkDeviceSize newSize);
|
||||
void RecordSetAllocationUserData(uint32_t frameIndex,
|
||||
VmaAllocation allocation,
|
||||
const void* pUserData);
|
||||
|
@ -5763,6 +5799,10 @@ public:
|
|||
// Main deallocation function.
|
||||
void FreeMemory(const VmaAllocation allocation);
|
||||
|
||||
VkResult ResizeAllocation(
|
||||
const VmaAllocation alloc,
|
||||
VkDeviceSize newSize);
|
||||
|
||||
void CalculateStats(VmaStats* pStats);
|
||||
|
||||
#if VMA_STATS_STRING_ENABLED
|
||||
|
@ -6296,6 +6336,12 @@ void VmaAllocation_T::ChangeBlockAllocation(
|
|||
m_BlockAllocation.m_Offset = offset;
|
||||
}
|
||||
|
||||
void VmaAllocation_T::ChangeSize(VkDeviceSize newSize)
|
||||
{
|
||||
VMA_ASSERT(newSize > 0);
|
||||
m_Size = newSize;
|
||||
}
|
||||
|
||||
VkDeviceSize VmaAllocation_T::GetOffset() const
|
||||
{
|
||||
switch(m_Type)
|
||||
|
@ -7222,6 +7268,133 @@ void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
|
|||
VMA_ASSERT(0 && "Not found!");
|
||||
}
|
||||
|
||||
bool VmaBlockMetadata_Generic::ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize)
|
||||
{
|
||||
typedef VmaSuballocationList::iterator iter_type;
|
||||
for(iter_type suballocItem = m_Suballocations.begin();
|
||||
suballocItem != m_Suballocations.end();
|
||||
++suballocItem)
|
||||
{
|
||||
VmaSuballocation& suballoc = *suballocItem;
|
||||
if(suballoc.hAllocation == alloc)
|
||||
{
|
||||
iter_type nextItem = suballocItem;
|
||||
++nextItem;
|
||||
|
||||
// Should have been ensured on higher level.
|
||||
VMA_ASSERT(newSize != alloc->GetSize() && newSize > 0);
|
||||
|
||||
// Shrinking.
|
||||
if(newSize < alloc->GetSize())
|
||||
{
|
||||
const VkDeviceSize sizeDiff = suballoc.size - newSize;
|
||||
|
||||
// There is next item.
|
||||
if(nextItem != m_Suballocations.end())
|
||||
{
|
||||
// Next item is free.
|
||||
if(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||
{
|
||||
// Grow this next item backward.
|
||||
UnregisterFreeSuballocation(nextItem);
|
||||
nextItem->offset -= sizeDiff;
|
||||
nextItem->size += sizeDiff;
|
||||
RegisterFreeSuballocation(nextItem);
|
||||
}
|
||||
// Next item is not free.
|
||||
else
|
||||
{
|
||||
// Create free item after current one.
|
||||
VmaSuballocation newFreeSuballoc;
|
||||
newFreeSuballoc.hAllocation = VK_NULL_HANDLE;
|
||||
newFreeSuballoc.offset = suballoc.offset + newSize;
|
||||
newFreeSuballoc.size = sizeDiff;
|
||||
newFreeSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
|
||||
iter_type newFreeSuballocIt = m_Suballocations.insert(nextItem, newFreeSuballoc);
|
||||
RegisterFreeSuballocation(newFreeSuballocIt);
|
||||
|
||||
++m_FreeCount;
|
||||
}
|
||||
}
|
||||
// This is the last item.
|
||||
else
|
||||
{
|
||||
// Create free item at the end.
|
||||
VmaSuballocation newFreeSuballoc;
|
||||
newFreeSuballoc.hAllocation = VK_NULL_HANDLE;
|
||||
newFreeSuballoc.offset = suballoc.offset + newSize;
|
||||
newFreeSuballoc.size = sizeDiff;
|
||||
newFreeSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
|
||||
m_Suballocations.push_back(newFreeSuballoc);
|
||||
|
||||
iter_type newFreeSuballocIt = m_Suballocations.end();
|
||||
RegisterFreeSuballocation(--newFreeSuballocIt);
|
||||
|
||||
++m_FreeCount;
|
||||
}
|
||||
|
||||
suballoc.size = newSize;
|
||||
m_SumFreeSize += sizeDiff;
|
||||
}
|
||||
// Growing.
|
||||
else
|
||||
{
|
||||
const VkDeviceSize sizeDiff = newSize - suballoc.size;
|
||||
|
||||
// There is next item.
|
||||
if(nextItem != m_Suballocations.end())
|
||||
{
|
||||
// Next item is free.
|
||||
if(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)
|
||||
{
|
||||
// There is not enough free space, including margin.
|
||||
if(nextItem->size < sizeDiff + VMA_DEBUG_MARGIN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// There is more free space than required.
|
||||
if(nextItem->size > sizeDiff)
|
||||
{
|
||||
// Move and shrink this next item.
|
||||
UnregisterFreeSuballocation(nextItem);
|
||||
nextItem->offset += sizeDiff;
|
||||
nextItem->size -= sizeDiff;
|
||||
RegisterFreeSuballocation(nextItem);
|
||||
}
|
||||
// There is exactly the amount of free space required.
|
||||
else
|
||||
{
|
||||
// Remove this next free item.
|
||||
UnregisterFreeSuballocation(nextItem);
|
||||
m_Suballocations.erase(nextItem);
|
||||
--m_FreeCount;
|
||||
}
|
||||
}
|
||||
// Next item is not free - there is no space to grow.
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// This is the last item - there is no space to grow.
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
suballoc.size = newSize;
|
||||
m_SumFreeSize -= sizeDiff;
|
||||
}
|
||||
|
||||
// We cannot call Validate() here because alloc object is updated to new size outside of this call.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
VMA_ASSERT(0 && "Not found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
|
||||
{
|
||||
VkDeviceSize lastSize = 0;
|
||||
|
@ -11368,7 +11541,7 @@ VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
|
|||
|
||||
// Write header.
|
||||
fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
|
||||
fprintf(m_File, "%s\n", "1,3");
|
||||
fprintf(m_File, "%s\n", "1,4");
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
@ -11524,6 +11697,20 @@ void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
|
|||
Flush();
|
||||
}
|
||||
|
||||
void VmaRecorder::RecordResizeAllocation(
|
||||
uint32_t frameIndex,
|
||||
VmaAllocation allocation,
|
||||
VkDeviceSize newSize)
|
||||
{
|
||||
CallParams callParams;
|
||||
GetBasicParams(callParams);
|
||||
|
||||
VmaMutexLock lock(m_FileMutex, m_UseMutex);
|
||||
fprintf(m_File, "%u,%.3f,%u,vmaResizeAllocation,%p,%llu\n", callParams.threadId, callParams.time, frameIndex,
|
||||
allocation, newSize);
|
||||
Flush();
|
||||
}
|
||||
|
||||
void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
|
||||
VmaAllocation allocation,
|
||||
const void* pUserData)
|
||||
|
@ -12487,6 +12674,40 @@ void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
|
|||
vma_delete(this, allocation);
|
||||
}
|
||||
|
||||
VkResult VmaAllocator_T::ResizeAllocation(
|
||||
const VmaAllocation alloc,
|
||||
VkDeviceSize newSize)
|
||||
{
|
||||
if(newSize == 0 || alloc->GetLastUseFrameIndex() == VMA_FRAME_INDEX_LOST)
|
||||
{
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
if(newSize == alloc->GetSize())
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
switch(alloc->GetType())
|
||||
{
|
||||
case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
|
||||
return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||
case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
|
||||
if(alloc->GetBlock()->m_pMetadata->ResizeAllocation(alloc, newSize))
|
||||
{
|
||||
alloc->ChangeSize(newSize);
|
||||
VMA_HEAVY_ASSERT(alloc->GetBlock()->m_pMetadata->Validate());
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return VK_ERROR_OUT_OF_POOL_MEMORY;
|
||||
}
|
||||
default:
|
||||
VMA_ASSERT(0);
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
}
|
||||
|
||||
void VmaAllocator_T::CalculateStats(VmaStats* pStats)
|
||||
{
|
||||
// Initialize.
|
||||
|
@ -13889,6 +14110,30 @@ void vmaFreeMemory(
|
|||
allocator->FreeMemory(allocation);
|
||||
}
|
||||
|
||||
VkResult vmaResizeAllocation(
|
||||
VmaAllocator allocator,
|
||||
VmaAllocation allocation,
|
||||
VkDeviceSize newSize)
|
||||
{
|
||||
VMA_ASSERT(allocator && allocation);
|
||||
|
||||
VMA_DEBUG_LOG("vmaResizeAllocation");
|
||||
|
||||
VMA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||
|
||||
#if VMA_RECORDING_ENABLED
|
||||
if(allocator->GetRecorder() != VMA_NULL)
|
||||
{
|
||||
allocator->GetRecorder()->RecordResizeAllocation(
|
||||
allocator->GetCurrentFrameIndex(),
|
||||
allocation,
|
||||
newSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
return allocator->ResizeAllocation(allocation, newSize);
|
||||
}
|
||||
|
||||
void vmaGetAllocationInfo(
|
||||
VmaAllocator allocator,
|
||||
VmaAllocation allocation,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue