Delete empty block unconditionally if budget is exceeded.

Also fixed crash when freeing lost allocation.
This commit is contained in:
Adam Sawicki 2019-11-13 15:20:31 +01:00
parent e6e3329a58
commit 4f900cd1b3

View File

@ -12149,6 +12149,14 @@ void VmaBlockVector::Free(
{ {
VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL; VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
bool budgetExceeded = false;
{
const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
VmaBudget heapBudget = {};
m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
budgetExceeded = heapBudget.usage >= heapBudget.budget;
}
// Scope for lock. // Scope for lock.
{ {
VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
@ -12171,11 +12179,12 @@ void VmaBlockVector::Free(
VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex); VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex);
const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount;
// pBlock became empty after this deallocation. // pBlock became empty after this deallocation.
if(pBlock->m_pMetadata->IsEmpty()) if(pBlock->m_pMetadata->IsEmpty())
{ {
// Already has empty Allocation. We don't want to have two, so delete this one. // Already has empty block. We don't want to have two, so delete this one.
if(m_HasEmptyBlock && m_Blocks.size() > m_MinBlockCount) if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock)
{ {
pBlockToDelete = pBlock; pBlockToDelete = pBlock;
Remove(pBlock); Remove(pBlock);
@ -12188,10 +12197,10 @@ void VmaBlockVector::Free(
} }
// pBlock didn't become empty, but we have another empty block - find and free that one. // pBlock didn't become empty, but we have another empty block - find and free that one.
// (This is optional, heuristics.) // (This is optional, heuristics.)
else if(m_HasEmptyBlock) else if(m_HasEmptyBlock && canDeleteBlock)
{ {
VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back(); VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
if(pLastBlock->m_pMetadata->IsEmpty() && m_Blocks.size() > m_MinBlockCount) if(pLastBlock->m_pMetadata->IsEmpty())
{ {
pBlockToDelete = pLastBlock; pBlockToDelete = pLastBlock;
m_Blocks.pop_back(); m_Blocks.pop_back();
@ -12202,11 +12211,11 @@ void VmaBlockVector::Free(
IncrementallySortBlocks(); IncrementallySortBlocks();
} }
// Destruction of a free Allocation. Deferred until this point, outside of mutex // Destruction of a free block. Deferred until this point, outside of mutex
// lock, for performance reason. // lock, for performance reason.
if(pBlockToDelete != VMA_NULL) if(pBlockToDelete != VMA_NULL)
{ {
VMA_DEBUG_LOG(" Deleted empty allocation"); VMA_DEBUG_LOG(" Deleted empty block");
pBlockToDelete->Destroy(m_hAllocator); pBlockToDelete->Destroy(m_hAllocator);
vma_delete(m_hAllocator, pBlockToDelete); vma_delete(m_hAllocator, pBlockToDelete);
} }
@ -15223,8 +15232,11 @@ void VmaAllocator_T::FreeMemory(
} }
} }
if(allocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
{
m_Budget.m_AllocationBytes[MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex())] -= allocation->GetSize(); m_Budget.m_AllocationBytes[MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex())] -= allocation->GetSize();
++m_Budget.m_OperationsSinceBudgetFetch; ++m_Budget.m_OperationsSinceBudgetFetch;
}
allocation->SetUserData(this, VMA_NULL); allocation->SetUserData(this, VMA_NULL);
allocation->Dtor(); allocation->Dtor();
m_AllocationObjectAllocator.Free(allocation); m_AllocationObjectAllocator.Free(allocation);