Optimization: dedicated allocations are on an intrusive double linked list not sorted vector
Added class VmaIntrusiveLinkedList, struct VmaDedicatedAllocationListItemTraits.
diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h
index 4876538..629f411 100644
--- a/src/vk_mem_alloc.h
+++ b/src/vk_mem_alloc.h
@@ -6009,6 +6009,222 @@
#endif // #if VMA_USE_STL_LIST
////////////////////////////////////////////////////////////////////////////////
+// class VmaIntrusiveLinkedList
+
+/*
+Expected interface of ItemTypeTraits:
+struct MyItemTypeTraits
+{
+typedef MyItem ItemType;
+static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; }
+static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; }
+static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; }
+static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; }
+};
+*/
+template<typename ItemTypeTraits>
+class VmaIntrusiveLinkedList
+{
+public:
+ typedef typename ItemTypeTraits::ItemType ItemType;
+ static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
+ static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
+ // Movable, not copyable.
+ VmaIntrusiveLinkedList() { }
+ VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
+ VmaIntrusiveLinkedList(VmaIntrusiveLinkedList<ItemTypeTraits>&& src) :
+ m_First(src.m_First), m_Last(src.m_Last), m_Count(src.m_Count)
+ {
+ src.m_First = src.m_Last = VMA_NULL;
+ src.m_Count = 0;
+ }
+ ~VmaIntrusiveLinkedList()
+ {
+ VMA_HEAVY_ASSERT(IsEmpty());
+ }
+ VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
+ VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(VmaIntrusiveLinkedList<ItemTypeTraits>&& src)
+ {
+ if(&src != this)
+ {
+ VMA_HEAVY_ASSERT(IsEmpty());
+ m_First = src.m_First;
+ m_Last = src.m_Last;
+ m_Count = src.m_Count;
+ src.m_First = src.m_Last = VMA_NULL;
+ src.m_Count = 0;
+ }
+ return *this;
+ }
+ void RemoveAll()
+ {
+ if(!IsEmpty())
+ {
+ ItemType* item = m_Back;
+ while(item != VMA_NULL)
+ {
+ ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
+ ItemTypeTraits::AccessPrev(item) = VMA_NULL;
+ ItemTypeTraits::AccessNext(item) = VMA_NULL;
+ item = prevItem;
+ }
+ m_Front = VMA_NULL;
+ m_Back = VMA_NULL;
+ m_Count = 0;
+ }
+ }
+ size_t GetCount() const { return m_Count; }
+ bool IsEmpty() const { return m_Count == 0; }
+ ItemType* Front() { return m_Front; }
+ const ItemType* Front() const { return m_Front; }
+ ItemType* Back() { return m_Back; }
+ const ItemType* Back() const { return m_Back; }
+ void PushBack(ItemType* item)
+ {
+ VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
+ if(IsEmpty())
+ {
+ m_Front = item;
+ m_Back = item;
+ m_Count = 1;
+ }
+ else
+ {
+ ItemTypeTraits::AccessPrev(item) = m_Back;
+ ItemTypeTraits::AccessNext(m_Back) = item;
+ m_Back = item;
+ ++m_Count;
+ }
+ }
+ void PushFront(ItemType* item)
+ {
+ VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
+ if(IsEmpty())
+ {
+ m_Front = item;
+ m_Back = item;
+ m_Count = 1;
+ }
+ else
+ {
+ ItemTypeTraits::AccessNext(item) = m_Front;
+ ItemTypeTraits::AccessPrev(m_Front) = item;
+ m_Front = item;
+ ++m_Count;
+ }
+ }
+ ItemType* PopBack()
+ {
+ VMA_HEAVY_ASSERT(m_Count > 0);
+ ItemType* const backItem = m_Back;
+ ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
+ if(prevItem != VMA_NULL)
+ {
+ ItemTypeTraits::AccessNext(prevItem) = VMA_NULL;
+ }
+ m_Back = prevItem;
+ --m_Count;
+ ItemTypeTraits::AccessPrev(backItem) = VMA_NULL;
+ ItemTypeTraits::AccessNext(backItem) = VMA_NULL;
+ return backItem;
+ }
+ ItemType* PopFront()
+ {
+ VMA_HEAVY_ASSERT(m_Count > 0);
+ ItemType* const frontItem = m_Front;
+ ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
+ if(nextItem != VMA_NULL)
+ {
+ ItemTypeTraits::AccessPrev(nextItem) = VMA_NULL;
+ }
+ m_Front = nextItem;
+ --m_Count;
+ ItemTypeTraits::AccessPrev(frontItem) = VMA_NULL;
+ ItemTypeTraits::AccessNext(frontItem) = VMA_NULL;
+ return frontItem;
+ }
+
+ // MyItem can be null - it means PushBack.
+ void InsertBefore(ItemType* existingItem, ItemType* newItem)
+ {
+ VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
+ if(existingItem != VMA_NULL)
+ {
+ ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
+ ItemTypeTraits::AccessPrev(newItem) = prevItem;
+ ItemTypeTraits::AccessNext(newItem) = existingItem;
+ ItemTypeTraits::AccessPrev(existingItem) = newItem;
+ if(prevItem != VMA_NULL)
+ {
+ ItemTypeTraits::AccessNext(prevItem) = newItem;
+ }
+ else
+ {
+ VMA_HEAVY_ASSERT(m_Front == existingItem);
+ m_Front = newItem;
+ }
+ ++m_Count;
+ }
+ else
+ PushBack(newItem);
+ }
+ // MyItem can be null - it means PushFront.
+ void InsertAfter(ItemType* existingItem, ItemType* newItem)
+ {
+ VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
+ if(existingItem != VMA_NULL)
+ {
+ ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
+ ItemTypeTraits::AccessNext(newItem) = nextItem;
+ ItemTypeTraits::AccessPrev(newItem) = existingItem;
+ ItemTypeTraits::AccessNext(existingItem) = newItem;
+ if(nextItem != VMA_NULL)
+ {
+ ItemTypeTraits::AccessPrev(nextItem) = newItem;
+ }
+ else
+ {
+ VMA_HEAVY_ASSERT(m_Back == existingItem);
+ m_Back = newItem;
+ }
+ ++m_Count;
+ }
+ else
+ return PushFront(newItem);
+ }
+ void Remove(ItemType* item)
+ {
+ VMA_HEAVY_ASSERT(item != VMA_NULL && m_Count > 0);
+ if(ItemTypeTraits::GetPrev(item) != VMA_NULL)
+ {
+ ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
+ }
+ else
+ {
+ VMA_HEAVY_ASSERT(m_Front == item);
+ m_Front = ItemTypeTraits::GetNext(item);
+ }
+
+ if(ItemTypeTraits::GetNext(item) != VMA_NULL)
+ {
+ ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
+ }
+ else
+ {
+ VMA_HEAVY_ASSERT(m_Back == item);
+ m_Back = ItemTypeTraits::GetPrev(item);
+ }
+ ItemTypeTraits::AccessPrev(item) = VMA_NULL;
+ ItemTypeTraits::AccessNext(item) = VMA_NULL;
+ --m_Count;
+ }
+private:
+ ItemType* m_Front = VMA_NULL;
+ ItemType* m_Back = VMA_NULL;
+ size_t m_Count = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
// class VmaMap
// Unused in this version.
@@ -6222,6 +6438,8 @@
m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
m_DedicatedAllocation.m_hMemory = hMemory;
m_DedicatedAllocation.m_pMappedData = pMappedData;
+ m_DedicatedAllocation.m_Prev = VMA_NULL;
+ m_DedicatedAllocation.m_Next = VMA_NULL;
}
ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
@@ -6319,6 +6537,8 @@
{
VkDeviceMemory m_hMemory;
void* m_pMappedData; // Not null means memory is mapped.
+ VmaAllocation_T* m_Prev;
+ VmaAllocation_T* m_Next;
};
union
@@ -6335,6 +6555,32 @@
#endif
void FreeUserDataString(VmaAllocator hAllocator);
+
+ friend struct VmaDedicatedAllocationListItemTraits;
+};
+
+struct VmaDedicatedAllocationListItemTraits
+{
+ typedef VmaAllocation_T ItemType;
+ static ItemType* GetPrev(const ItemType* item)
+ {
+ VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
+ return item->m_DedicatedAllocation.m_Prev;
+ }
+ static ItemType* GetNext(const ItemType* item)
+ {
+ VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
+ return item->m_DedicatedAllocation.m_Next;
+ }
+ static ItemType*& AccessPrev(ItemType* item)
+ {
+ VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
+ return item->m_DedicatedAllocation.m_Prev;
+ }
+ static ItemType*& AccessNext(ItemType* item){
+ VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
+ return item->m_DedicatedAllocation.m_Next;
+ }
};
/*
@@ -7909,9 +8155,8 @@
// Default pools.
VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
- // Each vector is sorted by memory (handle value).
- typedef VmaVector< VmaAllocation, VmaStlAllocator<VmaAllocation> > AllocationVectorType;
- AllocationVectorType* m_pDedicatedAllocations[VK_MAX_MEMORY_TYPES];
+ typedef VmaIntrusiveLinkedList<VmaDedicatedAllocationListItemTraits> DedicatedAllocationLinkedList;
+ DedicatedAllocationLinkedList m_DedicatedAllocations[VK_MAX_MEMORY_TYPES];
VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
VmaCurrentBudgetData m_Budget;
@@ -15803,7 +16048,6 @@
memset(&m_MemProps, 0, sizeof(m_MemProps));
memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
- memset(&m_pDedicatedAllocations, 0, sizeof(m_pDedicatedAllocations));
memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions));
if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
@@ -15862,8 +16106,6 @@
0.5f); // priority (0.5 is the default per Vulkan spec)
// No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here,
// becase minBlockCount is 0.
- m_pDedicatedAllocations[memTypeIndex] = vma_new(this, AllocationVectorType)(VmaStlAllocator<VmaAllocation>(GetAllocationCallbacks()));
-
}
}
@@ -15918,15 +16160,14 @@
VMA_ASSERT(m_Pools.empty());
- for(size_t i = GetMemoryTypeCount(); i--; )
+ for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
{
- if(m_pDedicatedAllocations[i] != VMA_NULL && !m_pDedicatedAllocations[i]->empty())
+ if(!m_DedicatedAllocations[memTypeIndex].IsEmpty())
{
VMA_ASSERT(0 && "Unfreed dedicated allocations found.");
}
- vma_delete(this, m_pDedicatedAllocations[i]);
- vma_delete(this, m_pBlockVectors[i]);
+ vma_delete(this, m_pBlockVectors[memTypeIndex]);
}
}
@@ -16382,14 +16623,13 @@
if(res == VK_SUCCESS)
{
- // Register them in m_pDedicatedAllocations.
+ // Register them in m_DedicatedAllocations.
{
VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
- AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
- VMA_ASSERT(pDedicatedAllocations);
+ DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
{
- VmaVectorInsertSorted<VmaPointerLess>(*pDedicatedAllocations, pAllocations[allocIndex]);
+ dedicatedAllocations.PushBack(pAllocations[allocIndex]);
}
}
@@ -16774,12 +17014,12 @@
{
const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
- AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
- VMA_ASSERT(pDedicatedAllocVector);
- for(size_t allocIndex = 0, allocCount = pDedicatedAllocVector->size(); allocIndex < allocCount; ++allocIndex)
+ DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
+ for(VmaAllocation alloc = dedicatedAllocList.Front();
+ alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
{
VmaStatInfo allocationStatInfo;
- (*pDedicatedAllocVector)[allocIndex]->DedicatedAllocCalcStatsInfo(allocationStatInfo);
+ alloc->DedicatedAllocCalcStatsInfo(allocationStatInfo);
VmaAddStatInfo(pStats->total, allocationStatInfo);
VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
@@ -17501,10 +17741,8 @@
const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
{
VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
- AllocationVectorType* const pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
- VMA_ASSERT(pDedicatedAllocations);
- bool success = VmaVectorRemoveSorted<VmaPointerLess>(*pDedicatedAllocations, allocation);
- VMA_ASSERT(success);
+ DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
+ dedicatedAllocations.Remove(allocation);
}
VkDeviceMemory hMemory = allocation->GetMemory();
@@ -17716,9 +17954,8 @@
for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
{
VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
- AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
- VMA_ASSERT(pDedicatedAllocVector);
- if(pDedicatedAllocVector->empty() == false)
+ DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
+ if(!dedicatedAllocList.IsEmpty())
{
if(dedicatedAllocationsStarted == false)
{
@@ -17733,11 +17970,11 @@
json.BeginArray();
- for(size_t i = 0; i < pDedicatedAllocVector->size(); ++i)
+ for(VmaAllocation alloc = dedicatedAllocList.Front();
+ alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
{
json.BeginObject(true);
- const VmaAllocation hAlloc = (*pDedicatedAllocVector)[i];
- hAlloc->PrintParameters(json);
+ alloc->PrintParameters(json);
json.EndObject();
}