Skip to content

Commit a01d458

Browse files
VmaBlockMetadata_Buddy: Introduced m_LevelCount to limit number of levels in use by particular memory block, considering new constant MIN_NODE_SIZE.
1 parent d6e6d6b commit a01d458

2 files changed

Lines changed: 33 additions & 6 deletions

File tree

src/Tests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4160,6 +4160,13 @@ static void BasicTestBuddyAllocator()
41604160
&newBufInfo.Buffer, &newBufInfo.Allocation, &allocInfo);
41614161
assert(res == VK_SUCCESS);
41624162
bufInfo.push_back(newBufInfo);
4163+
4164+
// Test very small allocation, smaller than minimum node size.
4165+
bufCreateInfo.size = 1;
4166+
res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo,
4167+
&newBufInfo.Buffer, &newBufInfo.Allocation, &allocInfo);
4168+
assert(res == VK_SUCCESS);
4169+
bufInfo.push_back(newBufInfo);
41634170

41644171
VmaPoolStats stats = {};
41654172
vmaGetPoolStats(g_hAllocator, pool, &stats);

src/vk_mem_alloc.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
49784980
class 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

50305032
private:
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

92809299
VkDeviceSize 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

94949513
bool 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

Comments
 (0)