Implemeneted VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT, VMA_DEFRAGMENTATION_OPTIMAL_ALGORITHM_BIT. Not tested yet.
Added VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET.
diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h
index f1974a6..eae44ae 100644
--- a/src/vk_mem_alloc.h
+++ b/src/vk_mem_alloc.h
@@ -2585,7 +2585,7 @@
Defragmentation will be done as fast and move as little allocations and bytes as possible while
still providing some benefits.
*/
- VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT = 0x000010000,
+ VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT = 0x00001000,
/** Add this flag to change defragmentation algorithm to optimal rather than default (balanced).
This algorithm will favor quality of defragmentation over speed.
Allocations will be as perfectly compacted as possible.
@@ -3240,6 +3240,8 @@
END OF CONFIGURATION
*/
+static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
+
static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
@@ -4973,7 +4975,8 @@
bool upperAddress,
VmaSuballocationType allocType,
bool canMakeOtherLost,
- uint32_t strategy, // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* flags.
+ // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags.
+ uint32_t strategy,
VmaAllocationRequest* pAllocationRequest) = 0;
virtual bool MakeRequestedAllocationsLost(
@@ -5707,7 +5710,8 @@
VmaDefragmentationAlgorithm(
VmaAllocator hAllocator,
VmaBlockVector* pBlockVector,
- uint32_t currentFrameIndex);
+ uint32_t currentFrameIndex,
+ uint32_t algorithmFlags); // Zero or one of VMA_DEFRAGMENTATION_*_ALGORITHM_BIT.
virtual ~VmaDefragmentationAlgorithm();
void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
@@ -5724,6 +5728,7 @@
VmaAllocator const m_hAllocator;
VmaBlockVector* const m_pBlockVector;
const uint32_t m_CurrentFrameIndex;
+ const uint32_t m_AlgorithmFlags;
VkDeviceSize m_BytesMoved;
uint32_t m_AllocationsMoved;
@@ -5748,6 +5753,14 @@
}
};
+ struct AllocationInfoOffsetGreater
+ {
+ bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
+ {
+ return lhs.m_hAllocation->GetOffset() > rhs.m_hAllocation->GetOffset();
+ }
+ };
+
// Used between AddAllocation and Defragment.
VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
@@ -5777,6 +5790,11 @@
{
VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
}
+
+ void SortAllocationsByOffsetDescending()
+ {
+ VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoOffsetGreater());
+ }
};
struct BlockPointerLess
@@ -5821,6 +5839,8 @@
VkDeviceSize maxBytesToMove,
uint32_t maxAllocationsToMove);
+ size_t CalcBlocksWithNonMovableCount() const;
+
static bool MoveMakesSense(
size_t dstBlockIndex, VkDeviceSize dstOffset,
size_t srcBlockIndex, VkDeviceSize srcOffset);
@@ -5857,7 +5877,8 @@
VmaAllocator hAllocator,
VmaPool hCustomPool, // Optional.
VmaBlockVector* pBlockVector,
- uint32_t currFrameIndex);
+ uint32_t currFrameIndex,
+ uint32_t algorithmFlags); // Zero or one of VMA_DEFRAGMENTATION_*_ALGORITHM_BIT.
~VmaBlockVectorDefragmentationContext();
VmaPool GetCustomPool() const { return m_hCustomPool; }
@@ -5882,6 +5903,7 @@
VmaDefragmentationContext_T(
VmaAllocator hAllocator,
uint32_t currFrameIndex,
+ uint32_t algorithmFlags,
VmaDefragmentationStats* pStats);
~VmaDefragmentationContext_T();
@@ -5904,6 +5926,7 @@
private:
const VmaAllocator m_hAllocator;
const uint32_t m_CurrFrameIndex;
+ const uint32_t m_AlgorithmFlags;
VmaDefragmentationStats* const m_pStats;
// Owner of these objects.
VmaBlockVectorDefragmentationContext* m_DefaultPoolContexts[VK_MAX_MEMORY_TYPES];
@@ -7339,6 +7362,31 @@
}
}
}
+ else if(strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET)
+ {
+ for(VmaSuballocationList::iterator it = m_Suballocations.begin();
+ it != m_Suballocations.end();
+ ++it)
+ {
+ if(it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation(
+ currentFrameIndex,
+ frameInUseCount,
+ bufferImageGranularity,
+ allocSize,
+ allocAlignment,
+ allocType,
+ it,
+ false, // canMakeOtherLost
+ &pAllocationRequest->offset,
+ &pAllocationRequest->itemsToMakeLostCount,
+ &pAllocationRequest->sumFreeSize,
+ &pAllocationRequest->sumItemSize))
+ {
+ pAllocationRequest->item = it;
+ return true;
+ }
+ }
+ }
else // WORST_FIT, FIRST_FIT
{
// Search staring from biggest suballocations.
@@ -11785,10 +11833,12 @@
VmaDefragmentationAlgorithm::VmaDefragmentationAlgorithm(
VmaAllocator hAllocator,
VmaBlockVector* pBlockVector,
- uint32_t currentFrameIndex) :
+ uint32_t currentFrameIndex,
+ uint32_t algorithmFlags) :
m_hAllocator(hAllocator),
m_pBlockVector(pBlockVector),
m_CurrentFrameIndex(currentFrameIndex),
+ m_AlgorithmFlags(algorithmFlags),
m_BytesMoved(0),
m_AllocationsMoved(0),
m_Allocations(VmaStlAllocator<AllocationInfo>(hAllocator->GetAllocationCallbacks())),
@@ -11822,19 +11872,43 @@
return VK_SUCCESS;
}
+ uint32_t strategy = UINT32_MAX;
+ switch(m_AlgorithmFlags)
+ {
+ case VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT:
+ strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
+ break;
+ case VMA_DEFRAGMENTATION_OPTIMAL_ALGORITHM_BIT:
+ strategy = VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET;
+ break;
+ default:
+ strategy = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT;
+ }
+
+ size_t srcBlockMinIndex = 0;
+ // When FAST_ALGORITHM, move allocations from only last out of blocks that contain non-movable allocations.
+ if(m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT)
+ {
+ const size_t blocksWithNonMovableCount = CalcBlocksWithNonMovableCount();
+ if(blocksWithNonMovableCount > 0)
+ {
+ srcBlockMinIndex = blocksWithNonMovableCount - 1;
+ }
+ }
+
size_t srcBlockIndex = m_Blocks.size() - 1;
size_t srcAllocIndex = SIZE_MAX;
for(;;)
{
// 1. Find next allocation to move.
// 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
- // 1.2. Then start from last to first m_Allocations - they are sorted from largest to smallest.
+ // 1.2. Then start from last to first m_Allocations.
while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
{
if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
{
// Finished: no more allocations to process.
- if(srcBlockIndex == 0)
+ if(srcBlockIndex == srcBlockMinIndex)
{
return VK_SUCCESS;
}
@@ -11872,7 +11946,7 @@
false, // upperAddress
suballocType,
false, // canMakeOtherLost
- VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT,
+ strategy,
&dstAllocRequest) &&
MoveMakesSense(
dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
@@ -11939,6 +12013,19 @@
}
}
+size_t VmaDefragmentationAlgorithm::CalcBlocksWithNonMovableCount() const
+{
+ size_t result = 0;
+ for(size_t i = 0; i < m_Blocks.size(); ++i)
+ {
+ if(m_Blocks[i]->m_HasNonMovableAllocations)
+ {
+ ++result;
+ }
+ }
+ return result;
+}
+
VkResult VmaDefragmentationAlgorithm::Defragment(
VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
VkDeviceSize maxBytesToMove,
@@ -11987,15 +12074,23 @@
{
BlockInfo* pBlockInfo = m_Blocks[blockIndex];
pBlockInfo->CalcHasNonMovableAllocations();
- pBlockInfo->SortAllocationsBySizeDescecnding();
+ if((m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT) != 0)
+ {
+ pBlockInfo->SortAllocationsByOffsetDescending();
+ }
+ else
+ {
+ pBlockInfo->SortAllocationsBySizeDescecnding();
+ }
}
// Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
// Execute defragmentation rounds (the main part).
+ const uint32_t roundCount = (m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT) ? 1 : 2;
VkResult result = VK_SUCCESS;
- for(size_t round = 0; (round < 2) && (result == VK_SUCCESS); ++round)
+ for(uint32_t round = 0; (round < roundCount) && (result == VK_SUCCESS); ++round)
{
result = DefragmentRound(moves, maxBytesToMove, maxAllocationsToMove);
}
@@ -12029,7 +12124,8 @@
VmaAllocator hAllocator,
VmaPool hCustomPool,
VmaBlockVector* pBlockVector,
- uint32_t currFrameIndex) :
+ uint32_t currFrameIndex,
+ uint32_t algorithmFlags) :
res(VK_SUCCESS),
mutexLocked(false),
blockContexts(VmaStlAllocator<VmaBlockDefragmentationContext>(hAllocator->GetAllocationCallbacks())),
@@ -12039,7 +12135,7 @@
m_pAlgorithm(VMA_NULL)
{
m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm)(
- m_hAllocator, m_pBlockVector, currFrameIndex);
+ m_hAllocator, m_pBlockVector, currFrameIndex, algorithmFlags);
}
VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext()
@@ -12053,9 +12149,11 @@
VmaDefragmentationContext_T::VmaDefragmentationContext_T(
VmaAllocator hAllocator,
uint32_t currFrameIndex,
+ uint32_t algorithmFlags,
VmaDefragmentationStats* pStats) :
m_hAllocator(hAllocator),
m_CurrFrameIndex(currFrameIndex),
+ m_AlgorithmFlags(algorithmFlags),
m_pStats(pStats),
m_CustomPoolContexts(VmaStlAllocator<VmaBlockVectorDefragmentationContext*>(hAllocator->GetAllocationCallbacks()))
{
@@ -12119,7 +12217,8 @@
m_hAllocator,
hAllocPool,
&hAllocPool->m_BlockVector,
- m_CurrFrameIndex);
+ m_CurrFrameIndex,
+ m_AlgorithmFlags);
m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
}
}
@@ -12135,7 +12234,8 @@
m_hAllocator,
VMA_NULL, // hCustomPool
m_hAllocator->m_pBlockVectors[memTypeIndex],
- m_CurrFrameIndex);
+ m_CurrFrameIndex,
+ m_AlgorithmFlags);
m_DefaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx;
}
}
@@ -13476,8 +13576,9 @@
memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
}
+ const uint32_t algorithmFlags = info.flags & VMA_DEFRAGMENTATION_ALGORITHM_MASK;
*pContext = vma_new(this, VmaDefragmentationContext_T)(
- this, m_CurrentFrameIndex.load(), pStats);
+ this, m_CurrentFrameIndex.load(), algorithmFlags, pStats);
(*pContext)->AddAllocations(
info.allocationCount, info.pAllocations, info.pAllocationsChanged);