diff --git a/src/Tests.cpp b/src/Tests.cpp index 9286c5c..9f9a6da 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -4168,6 +4168,23 @@ static void BasicTestBuddyAllocator() assert(res == VK_SUCCESS); bufInfo.push_back(newBufInfo); + // Test some small allocation with alignment requirement. + { + VkMemoryRequirements memReq; + memReq.alignment = 256; + memReq.memoryTypeBits = UINT32_MAX; + memReq.size = 32; + + newBufInfo.Buffer = VK_NULL_HANDLE; + res = vmaAllocateMemory(g_hAllocator, &memReq, &allocCreateInfo, + &newBufInfo.Allocation, &allocInfo); + assert(res == VK_SUCCESS); + assert(allocInfo.offset % memReq.alignment == 0); + bufInfo.push_back(newBufInfo); + } + + //SaveAllocatorStatsToFile(L"TEST.json"); + VmaPoolStats stats = {}; vmaGetPoolStats(g_hAllocator, pool, &stats); int DBG = 0; // Set breakpoint here to inspect `stats`. diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h index 41a5a92..a11e654 100644 --- a/src/vk_mem_alloc.h +++ b/src/vk_mem_alloc.h @@ -9400,14 +9400,19 @@ bool VmaBlockMetadata_Buddy::CreateAllocationRequest( const uint32_t targetLevel = AllocSizeToLevel(allocSize); for(uint32_t level = targetLevel + 1; level--; ) { - if(m_FreeList[level].front != VMA_NULL) + for(Node* freeNode = m_FreeList[level].front; + freeNode != VMA_NULL; + freeNode = freeNode->free.next) { - pAllocationRequest->offset = m_FreeList[level].front->offset; - pAllocationRequest->sumFreeSize = LevelToNodeSize(level); - pAllocationRequest->sumItemSize = 0; - pAllocationRequest->itemsToMakeLostCount = 0; - pAllocationRequest->customData = (void*)(uintptr_t)level; - return true; + if(freeNode->offset % allocAlignment == 0) + { + pAllocationRequest->offset = freeNode->offset; + pAllocationRequest->sumFreeSize = LevelToNodeSize(level); + pAllocationRequest->sumItemSize = 0; + pAllocationRequest->itemsToMakeLostCount = 0; + pAllocationRequest->customData = (void*)(uintptr_t)level; + return true; + } } } @@ -9444,10 +9449,14 @@ void VmaBlockMetadata_Buddy::Alloc( { const uint32_t targetLevel = AllocSizeToLevel(allocSize); uint32_t currLevel = (uint32_t)(uintptr_t)request.customData; - VMA_ASSERT(m_FreeList[currLevel].front != VMA_NULL); + Node* currNode = m_FreeList[currLevel].front; - VMA_ASSERT(currNode->type == Node::TYPE_FREE); - VMA_ASSERT(currNode->offset == request.offset); + VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + while(currNode->offset != request.offset) + { + currNode = currNode->free.next; + VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + } // Go down, splitting free nodes. while(currLevel < targetLevel) @@ -9484,10 +9493,17 @@ void VmaBlockMetadata_Buddy::Alloc( //m_SumFreeSize -= LevelToNodeSize(currLevel) % 2; // Useful only when level node sizes can be non power of 2. ++currLevel; currNode = m_FreeList[currLevel].front; + + /* + We can be sure that currNode, as left child of node previously split, + also fullfills the alignment requirement. + */ } // Remove from free list. - VMA_ASSERT(currLevel == targetLevel && currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + VMA_ASSERT(currLevel == targetLevel && + currNode != VMA_NULL && + currNode->type == Node::TYPE_FREE); RemoveFromFreeList(currLevel, currNode); // Convert to allocation node.