@@ -4971,9 +4971,11 @@ class VmaBlockMetadata_Linear : public VmaBlockMetadata
49714971- m_UsableSize is this size aligned down to a power of two.
49724972 All allocations and calculations happen relative to m_UsableSize.
49734973- GetUnusableSize() is the difference between them.
4974- It is repoted as separate unused range.
4974+ It is repoted as separate, unused range, not available for allocations .
49754975
4976- Level 0 has block size = GetSize(). Level 1 has block size = GetSize() / 2 and so on...
4976+ Node at level 0 has size = m_UsableSize.
4977+ Each next level contains nodes with size 2 times smaller than current level.
4978+ m_LevelCount is the maximum number of levels to use in the current object.
49774979*/
49784980class VmaBlockMetadata_Buddy : public VmaBlockMetadata
49794981{
@@ -5028,7 +5030,8 @@ class VmaBlockMetadata_Buddy : public VmaBlockMetadata
50285030 virtual void FreeAtOffset (VkDeviceSize offset) { FreeAtOffset (VMA_NULL, offset); }
50295031
50305032private:
5031- static const size_t MAX_LEVELS = 30 ; // TODO
5033+ static const VkDeviceSize MIN_NODE_SIZE = 32 ;
5034+ static const size_t MAX_LEVELS = 30 ;
50325035
50335036 struct ValidationContext
50345037 {
@@ -5075,6 +5078,8 @@ class VmaBlockMetadata_Buddy : public VmaBlockMetadata
50755078
50765079 // Size of the memory block aligned down to a power of two.
50775080 VkDeviceSize m_UsableSize;
5081+ uint32_t m_LevelCount;
5082+
50785083 Node* m_Root;
50795084 struct {
50805085 Node* front;
@@ -9230,6 +9235,14 @@ void VmaBlockMetadata_Buddy::Init(VkDeviceSize size)
92309235 m_UsableSize = VmaPrevPow2 (size);
92319236 m_SumFreeSize = m_UsableSize;
92329237
9238+ // Calculate m_LevelCount.
9239+ m_LevelCount = 1 ;
9240+ while (m_LevelCount < MAX_LEVELS &&
9241+ LevelToNodeSize (m_LevelCount) >= MIN_NODE_SIZE)
9242+ {
9243+ ++m_LevelCount;
9244+ }
9245+
92339246 Node* rootNode = new Node ();
92349247 rootNode->offset = 0 ;
92359248 rootNode->type = Node::TYPE_FREE;
@@ -9252,7 +9265,7 @@ bool VmaBlockMetadata_Buddy::Validate() const
92529265 VMA_VALIDATE (m_SumFreeSize == ctx.calculatedSumFreeSize );
92539266
92549267 // Validate free node lists.
9255- for (uint32_t level = 0 ; level < MAX_LEVELS ; ++level)
9268+ for (uint32_t level = 0 ; level < m_LevelCount ; ++level)
92569269 {
92579270 VMA_VALIDATE (m_FreeList[level].front == VMA_NULL ||
92589271 m_FreeList[level].front ->free .prev == VMA_NULL);
@@ -9274,12 +9287,18 @@ bool VmaBlockMetadata_Buddy::Validate() const
92749287 }
92759288 }
92769289
9290+ // Validate that free lists ar higher levels are empty.
9291+ for (uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level)
9292+ {
9293+ VMA_VALIDATE (m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL);
9294+ }
9295+
92779296 return true ;
92789297}
92799298
92809299VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax () const
92819300{
9282- for (uint32_t level = 0 ; level < MAX_LEVELS ; ++level)
9301+ for (uint32_t level = 0 ; level < m_LevelCount ; ++level)
92839302 {
92849303 if (m_FreeList[level].front != VMA_NULL)
92859304 {
@@ -9493,6 +9512,7 @@ void VmaBlockMetadata_Buddy::DeleteNode(Node* node)
94939512
94949513bool VmaBlockMetadata_Buddy::ValidateNode (ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
94959514{
9515+ VMA_VALIDATE (level < m_LevelCount);
94969516 VMA_VALIDATE (curr->parent == parent);
94979517 VMA_VALIDATE ((curr->buddy == VMA_NULL) == (parent == VMA_NULL));
94989518 VMA_VALIDATE (curr->buddy == VMA_NULL || curr->buddy ->buddy == curr);
@@ -9540,7 +9560,7 @@ uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const
95409560 uint32_t level = 0 ;
95419561 VkDeviceSize currLevelNodeSize = m_UsableSize;
95429562 VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1 ;
9543- while (allocSize <= nextLevelNodeSize && level + 1 < MAX_LEVELS )
9563+ while (allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount )
95449564 {
95459565 ++level;
95469566 currLevelNodeSize = nextLevelNodeSize;
0 commit comments