Added macro VMA_VALIDATE to simplify validation methods. Implemented proper calculation of VmaBlockMetadata_Buddy::GetAllocationCount.
diff --git a/src/VmaUsage.h b/src/VmaUsage.h
index bd31938..ec74a34 100644
--- a/src/VmaUsage.h
+++ b/src/VmaUsage.h
@@ -16,7 +16,7 @@
include all public interface declarations. Example:
*/
-//#define VMA_HEAVY_ASSERT(expr) assert(expr)
+#define VMA_HEAVY_ASSERT(expr) assert(expr)
//#define VMA_USE_STL_CONTAINERS 1
//#define VMA_DEDICATED_ALLOCATION 0
//#define VMA_DEBUG_MARGIN 16
diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h
index 956e58d..53ee588 100644
--- a/src/vk_mem_alloc.h
+++ b/src/vk_mem_alloc.h
@@ -4670,6 +4670,11 @@
VkDeviceSize m_Size;
};
+#define VMA_VALIDATE(cond) do { if(!(cond)) { \
+ VMA_ASSERT(0 && "Validation failed: " ## #cond); \
+ return false; \
+ } } while(false)
+
class VmaBlockMetadata_Generic : public VmaBlockMetadata
{
VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic)
@@ -4950,7 +4955,7 @@
virtual void Init(VkDeviceSize size);
virtual bool Validate() const;
- virtual size_t GetAllocationCount() const;
+ virtual size_t GetAllocationCount() const { return m_AllocationCount; }
virtual VkDeviceSize GetSumFreeSize() const;
virtual VkDeviceSize GetUnusedRangeSizeMax() const;
virtual bool IsEmpty() const { return m_Root->type == Node::TYPE_FREE; }
@@ -4981,7 +4986,7 @@
virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
- virtual VkResult CheckCorruption(const void* pBlockData);
+ virtual VkResult CheckCorruption(const void* pBlockData) { return VK_ERROR_FEATURE_NOT_PRESENT; }
virtual void Alloc(
const VmaAllocationRequest& request,
@@ -4996,6 +5001,14 @@
private:
static const size_t MAX_LEVELS = 30; // TODO
+ struct ValidationContext
+ {
+ size_t calculatedAllocationCount;
+
+ ValidationContext() :
+ calculatedAllocationCount(0) { }
+ };
+
struct Node
{
VkDeviceSize offset;
@@ -5032,9 +5045,11 @@
Node* front;
Node* back;
} m_FreeList[MAX_LEVELS];
+ // Number of nodes in the tree with type == TYPE_ALLOCATION.
+ size_t m_AllocationCount;
void DeleteNode(Node* node);
- bool ValidateNode(const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;
+ bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;
uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const;
VkDeviceSize LevelToNodeSize(uint32_t level) const;
// Alloc passed just for validation. Can be null.
@@ -6580,10 +6595,7 @@
bool VmaBlockMetadata_Generic::Validate() const
{
- if(m_Suballocations.empty())
- {
- return false;
- }
+ VMA_VALIDATE(!m_Suballocations.empty());
// Expected offset of new suballocation as calculated from previous ones.
VkDeviceSize calculatedOffset = 0;
@@ -6604,22 +6616,13 @@
const VmaSuballocation& subAlloc = *suballocItem;
// Actual offset of this suballocation doesn't match expected one.
- if(subAlloc.offset != calculatedOffset)
- {
- return false;
- }
+ VMA_VALIDATE(subAlloc.offset == calculatedOffset);
const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
// Two adjacent free suballocations are invalid. They should be merged.
- if(prevFree && currFree)
- {
- return false;
- }
+ VMA_VALIDATE(!prevFree || !currFree);
- if(currFree != (subAlloc.hAllocation == VK_NULL_HANDLE))
- {
- return false;
- }
+ VMA_VALIDATE(currFree == (subAlloc.hAllocation == VK_NULL_HANDLE));
if(currFree)
{
@@ -6631,27 +6634,15 @@
}
// Margin required between allocations - every free space must be at least that large.
- if(subAlloc.size < VMA_DEBUG_MARGIN)
- {
- return false;
- }
+ VMA_VALIDATE(subAlloc.size >= VMA_DEBUG_MARGIN);
}
else
{
- if(subAlloc.hAllocation->GetOffset() != subAlloc.offset)
- {
- return false;
- }
- if(subAlloc.hAllocation->GetSize() != subAlloc.size)
- {
- return false;
- }
+ VMA_VALIDATE(subAlloc.hAllocation->GetOffset() == subAlloc.offset);
+ VMA_VALIDATE(subAlloc.hAllocation->GetSize() == subAlloc.size);
// Margin required between allocations - previous allocation must be free.
- if(VMA_DEBUG_MARGIN > 0 && !prevFree)
- {
- return false;
- }
+ VMA_VALIDATE(VMA_DEBUG_MARGIN == 0 || prevFree);
}
calculatedOffset += subAlloc.size;
@@ -6660,10 +6651,7 @@
// Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
// match expected one.
- if(m_FreeSuballocationsBySize.size() != freeSuballocationsToRegister)
- {
- return false;
- }
+ VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
VkDeviceSize lastSize = 0;
for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
@@ -6671,27 +6659,18 @@
VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
// Only free suballocations can be registered in m_FreeSuballocationsBySize.
- if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
- {
- return false;
- }
+ VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE);
// They must be sorted by size ascending.
- if(suballocItem->size < lastSize)
- {
- return false;
- }
+ VMA_VALIDATE(suballocItem->size >= lastSize);
lastSize = suballocItem->size;
}
// Check if totals match calculacted values.
- if(!ValidateFreeSuballocationList() ||
- (calculatedOffset != GetSize()) ||
- (calculatedSumFreeSize != m_SumFreeSize) ||
- (calculatedFreeCount != m_FreeCount))
- {
- return false;
- }
+ VMA_VALIDATE(ValidateFreeSuballocationList());
+ VMA_VALIDATE(calculatedOffset == GetSize());
+ VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
+ VMA_VALIDATE(calculatedFreeCount == m_FreeCount);
return true;
}
@@ -7101,22 +7080,9 @@
{
const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
- if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
- {
- VMA_ASSERT(0);
- return false;
- }
- if(it->size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- VMA_ASSERT(0);
- return false;
- }
- if(it->size < lastSize)
- {
- VMA_ASSERT(0);
- return false;
- }
-
+ VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE);
+ VMA_VALIDATE(it->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
+ VMA_VALIDATE(it->size >= lastSize);
lastSize = it->size;
}
return true;
@@ -7551,45 +7517,26 @@
const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- if(suballocations2nd.empty() != (m_2ndVectorMode == SECOND_VECTOR_EMPTY))
- {
- return false;
- }
- if(suballocations1st.empty() && !suballocations2nd.empty() &&
- m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- return false;
- }
+ VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
+ VMA_VALIDATE(!suballocations1st.empty() ||
+ suballocations2nd.empty() ||
+ m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
+
if(!suballocations1st.empty())
{
// Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
- if(suballocations1st[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
- {
- return false;
- }
+ VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].hAllocation != VK_NULL_HANDLE);
// Null item at the end should be just pop_back().
- if(suballocations1st.back().hAllocation == VK_NULL_HANDLE)
- {
- return false;
- }
+ VMA_VALIDATE(suballocations1st.back().hAllocation != VK_NULL_HANDLE);
}
if(!suballocations2nd.empty())
{
// Null item at the end should be just pop_back().
- if(suballocations2nd.back().hAllocation == VK_NULL_HANDLE)
- {
- return false;
- }
+ VMA_VALIDATE(suballocations2nd.back().hAllocation != VK_NULL_HANDLE);
}
- if(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount > suballocations1st.size())
- {
- return false;
- }
- if(m_2ndNullItemsCount > suballocations2nd.size())
- {
- return false;
- }
+ VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
+ VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
VkDeviceSize sumUsedSize = 0;
const size_t suballoc1stCount = suballocations1st.size();
@@ -7604,25 +7551,13 @@
const VmaSuballocation& suballoc = suballocations2nd[i];
const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
- if(currFree != (suballoc.hAllocation == VK_NULL_HANDLE))
- {
- return false;
- }
- if(suballoc.offset < offset)
- {
- return false;
- }
+ VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
+ VMA_VALIDATE(suballoc.offset >= offset);
if(!currFree)
{
- if(suballoc.hAllocation->GetOffset() != suballoc.offset)
- {
- return false;
- }
- if(suballoc.hAllocation->GetSize() != suballoc.size)
- {
- return false;
- }
+ VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
+ VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
sumUsedSize += suballoc.size;
}
else
@@ -7633,20 +7568,14 @@
offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
}
- if(nullItem2ndCount != m_2ndNullItemsCount)
- {
- return false;
- }
+ VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
}
for(size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
{
const VmaSuballocation& suballoc = suballocations1st[i];
- if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE ||
- suballoc.hAllocation != VK_NULL_HANDLE)
- {
- return false;
- }
+ VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE &&
+ suballoc.hAllocation == VK_NULL_HANDLE);
}
size_t nullItem1stCount = m_1stNullItemsBeginCount;
@@ -7656,29 +7585,14 @@
const VmaSuballocation& suballoc = suballocations1st[i];
const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
- if(currFree != (suballoc.hAllocation == VK_NULL_HANDLE))
- {
- return false;
- }
- if(suballoc.offset < offset)
- {
- return false;
- }
- if(i < m_1stNullItemsBeginCount && !currFree)
- {
- return false;
- }
+ VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
+ VMA_VALIDATE(suballoc.offset >= offset);
+ VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
if(!currFree)
{
- if(suballoc.hAllocation->GetOffset() != suballoc.offset)
- {
- return false;
- }
- if(suballoc.hAllocation->GetSize() != suballoc.size)
- {
- return false;
- }
+ VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
+ VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
sumUsedSize += suballoc.size;
}
else
@@ -7688,10 +7602,7 @@
offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
}
- if(nullItem1stCount != m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount)
- {
- return false;
- }
+ VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
{
@@ -7702,25 +7613,13 @@
const VmaSuballocation& suballoc = suballocations2nd[i];
const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
- if(currFree != (suballoc.hAllocation == VK_NULL_HANDLE))
- {
- return false;
- }
- if(suballoc.offset < offset)
- {
- return false;
- }
+ VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
+ VMA_VALIDATE(suballoc.offset >= offset);
if(!currFree)
{
- if(suballoc.hAllocation->GetOffset() != suballoc.offset)
- {
- return false;
- }
- if(suballoc.hAllocation->GetSize() != suballoc.size)
- {
- return false;
- }
+ VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
+ VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
sumUsedSize += suballoc.size;
}
else
@@ -7731,20 +7630,11 @@
offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
}
- if(nullItem2ndCount != m_2ndNullItemsCount)
- {
- return false;
- }
+ VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
}
- if(offset > GetSize())
- {
- return false;
- }
- if(m_SumFreeSize != GetSize() - sumUsedSize)
- {
- return false;
- }
+ VMA_VALIDATE(offset <= GetSize());
+ VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
return true;
}
@@ -9278,7 +9168,8 @@
// class VmaBlockMetadata_Buddy
VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) :
- m_Root(VMA_NULL)
+ m_Root(VMA_NULL),
+ m_AllocationCount(0)
{
memset(m_FreeList, 0, sizeof(m_FreeList));
}
@@ -9305,42 +9196,32 @@
bool VmaBlockMetadata_Buddy::Validate() const
{
// Validate tree.
- if(!ValidateNode(VMA_NULL, m_Root, 0, GetSize()))
+ ValidationContext ctx;
+ if(!ValidateNode(ctx, VMA_NULL, m_Root, 0, GetSize()))
{
- return false;
+ VMA_VALIDATE(false && "ValidateNode failed.");
}
+ VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount);
// Validate free node lists.
for(uint32_t level = 0; level < MAX_LEVELS; ++level)
{
- if(m_FreeList[level].front != VMA_NULL &&
- m_FreeList[level].front->free.prev != VMA_NULL)
- {
- return false;
- }
+ VMA_VALIDATE(m_FreeList[level].front == VMA_NULL ||
+ m_FreeList[level].front->free.prev == VMA_NULL);
for(Node* node = m_FreeList[level].front;
node != VMA_NULL;
node = node->free.next)
{
- if(node->type != Node::TYPE_FREE)
- {
- return false;
- }
+ VMA_VALIDATE(node->type == Node::TYPE_FREE);
if(node->free.next == VMA_NULL)
{
- if(m_FreeList[level].back != node)
- {
- return false;
- }
+ VMA_VALIDATE(m_FreeList[level].back == node);
}
else
{
- if(node->free.next->free.prev != node)
- {
- return false;
- }
+ VMA_VALIDATE(node->free.next->free.prev == node);
}
}
}
@@ -9348,11 +9229,6 @@
return true;
}
-size_t VmaBlockMetadata_Buddy::GetAllocationCount() const
-{
- return 0; // TODO
-}
-
VkDeviceSize VmaBlockMetadata_Buddy::GetSumFreeSize() const
{
return 0; // TODO
@@ -9453,11 +9329,6 @@
return 0; // TODO
}
-VkResult VmaBlockMetadata_Buddy::CheckCorruption(const void* pBlockData)
-{
- return VK_SUCCESS; // TODO
-}
-
void VmaBlockMetadata_Buddy::Alloc(
const VmaAllocationRequest& request,
VmaSuballocationType type,
@@ -9514,6 +9385,8 @@
// Convert to allocation node.
currNode->type = Node::TYPE_ALLOCATION;
currNode->allocation.alloc = hAllocation;
+
+ ++m_AllocationCount;
}
void VmaBlockMetadata_Buddy::DeleteNode(Node* node)
@@ -9527,56 +9400,36 @@
delete node;
}
-bool VmaBlockMetadata_Buddy::ValidateNode(const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
+bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
{
- if(curr->parent != parent)
- {
- return false;
- }
- if((curr->buddy == VMA_NULL) != (parent == VMA_NULL))
- {
- return false;
- }
- if(curr->buddy != VMA_NULL && curr->buddy->buddy != curr)
- {
- return false;
- }
+ VMA_VALIDATE(curr->parent == parent);
+ VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL));
+ VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr);
switch(curr->type)
{
case Node::TYPE_FREE:
// curr->free.prev, next are validated separately.
break;
case Node::TYPE_ALLOCATION:
- if(curr->allocation.alloc == VK_NULL_HANDLE)
- {
- return false;
- }
+ ++ctx.calculatedAllocationCount;
+ VMA_VALIDATE(curr->allocation.alloc != VK_NULL_HANDLE);
break;
case Node::TYPE_SPLIT:
{
const uint32_t childrenLevel = level + 1;
const VkDeviceSize childrenLevelNodeSize = levelNodeSize / 2;
const Node* const leftChild = curr->split.leftChild;
- if(leftChild == VMA_NULL)
+ VMA_VALIDATE(leftChild != VMA_NULL);
+ VMA_VALIDATE(leftChild->offset == curr->offset);
+ if(!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize))
{
- return false;
- }
- if(leftChild->offset != curr->offset)
- {
- return false;
- }
- if(!ValidateNode(curr, leftChild, childrenLevel, childrenLevelNodeSize))
- {
- return false;
+ VMA_VALIDATE(false && "ValidateNode for left child failed.");
}
const Node* const rightChild = leftChild->buddy;
- if(rightChild->offset != curr->offset + levelNodeSize)
+ VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize);
+ if(!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize))
{
- return false;
- }
- if(!ValidateNode(curr, rightChild, childrenLevel, childrenLevelNodeSize))
- {
- return false;
+ VMA_VALIDATE(false && "ValidateNode for right child failed.");
}
}
break;
@@ -9639,6 +9492,8 @@
VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION);
VMA_ASSERT(alloc == VK_NULL_HANDLE || node->allocation.alloc == alloc);
+ --m_AllocationCount;
+
node->type = Node::TYPE_FREE;
// Join free nodes if possible.
@@ -9828,11 +9683,8 @@
bool VmaDeviceMemoryBlock::Validate() const
{
- if((m_hMemory == VK_NULL_HANDLE) ||
- (m_pMetadata->GetSize() == 0))
- {
- return false;
- }
+ VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) &&
+ (m_pMetadata->GetSize() != 0));
return m_pMetadata->Validate();
}