@@ -2154,9 +2154,12 @@ typedef struct VmaBudget
21542154
21552155 /** \brief Sum size of all allocations created in particular heap, in bytes.
21562156
2157- Always less or equal than `blockBytes`.
2157+ Usually less or equal than `blockBytes`.
21582158 Difference `blockBytes - allocationBytes` is the amount of memory allocated but unused -
21592159 available for new allocations or wasted due to fragmentation.
2160+
2161+ It might be greater than `blockBytes` if there are some allocations in lost state, as they account
2162+ to this value as well.
21602163 */
21612164 VkDeviceSize allocationBytes;
21622165
@@ -5284,6 +5287,7 @@ struct VmaAllocation_T
52845287 {
52855288 m_Alignment = 1;
52865289 m_Size = 0;
5290+ m_MemoryTypeIndex = 0;
52875291 m_pUserData = VMA_NULL;
52885292 m_LastUseFrameIndex = currentFrameIndex;
52895293 m_Type = (uint8_t)ALLOCATION_TYPE_NONE;
@@ -5310,6 +5314,7 @@ struct VmaAllocation_T
53105314 VkDeviceSize offset,
53115315 VkDeviceSize alignment,
53125316 VkDeviceSize size,
5317+ uint32_t memoryTypeIndex,
53135318 VmaSuballocationType suballocationType,
53145319 bool mapped,
53155320 bool canBecomeLost)
@@ -5319,6 +5324,7 @@ struct VmaAllocation_T
53195324 m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
53205325 m_Alignment = alignment;
53215326 m_Size = size;
5327+ m_MemoryTypeIndex = memoryTypeIndex;
53225328 m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
53235329 m_SuballocationType = (uint8_t)suballocationType;
53245330 m_BlockAllocation.m_Block = block;
@@ -5331,6 +5337,7 @@ struct VmaAllocation_T
53315337 VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
53325338 VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
53335339 m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
5340+ m_MemoryTypeIndex = 0;
53345341 m_BlockAllocation.m_Block = VMA_NULL;
53355342 m_BlockAllocation.m_Offset = 0;
53365343 m_BlockAllocation.m_CanBecomeLost = true;
@@ -5356,9 +5363,9 @@ struct VmaAllocation_T
53565363 m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
53575364 m_Alignment = 0;
53585365 m_Size = size;
5366+ m_MemoryTypeIndex = memoryTypeIndex;
53595367 m_SuballocationType = (uint8_t)suballocationType;
53605368 m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
5361- m_DedicatedAllocation.m_MemoryTypeIndex = memoryTypeIndex;
53625369 m_DedicatedAllocation.m_hMemory = hMemory;
53635370 m_DedicatedAllocation.m_pMappedData = pMappedData;
53645371 }
@@ -5378,7 +5385,7 @@ struct VmaAllocation_T
53785385 }
53795386 VkDeviceSize GetOffset() const;
53805387 VkDeviceMemory GetMemory() const;
5381- uint32_t GetMemoryTypeIndex() const;
5388+ uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
53825389 bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
53835390 void* GetMappedData() const;
53845391 bool CanBecomeLost() const;
@@ -5437,6 +5444,7 @@ struct VmaAllocation_T
54375444 VkDeviceSize m_Size;
54385445 void* m_pUserData;
54395446 VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
5447+ uint32_t m_MemoryTypeIndex;
54405448 uint8_t m_Type; // ALLOCATION_TYPE
54415449 uint8_t m_SuballocationType; // VmaSuballocationType
54425450 // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
@@ -5455,7 +5463,6 @@ struct VmaAllocation_T
54555463 // Allocation for an object that has its own private VkDeviceMemory.
54565464 struct DedicatedAllocation
54575465 {
5458- uint32_t m_MemoryTypeIndex;
54595466 VkDeviceMemory m_hMemory;
54605467 void* m_pMappedData; // Not null means memory is mapped.
54615468 };
@@ -6964,6 +6971,23 @@ struct VmaCurrentBudgetData
69646971
69656972#if VMA_MEMORY_BUDGET
69666973 m_OperationsSinceBudgetFetch = 0;
6974+ #endif
6975+ }
6976+
6977+ void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
6978+ {
6979+ m_AllocationBytes[heapIndex] += allocationSize;
6980+ #if VMA_MEMORY_BUDGET
6981+ ++m_OperationsSinceBudgetFetch;
6982+ #endif
6983+ }
6984+
6985+ void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
6986+ {
6987+ VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME
6988+ m_AllocationBytes[heapIndex] -= allocationSize;
6989+ #if VMA_MEMORY_BUDGET
6990+ ++m_OperationsSinceBudgetFetch;
69676991#endif
69686992 }
69696993};
@@ -7715,20 +7739,6 @@ VkDeviceMemory VmaAllocation_T::GetMemory() const
77157739 }
77167740}
77177741
7718- uint32_t VmaAllocation_T::GetMemoryTypeIndex() const
7719- {
7720- switch(m_Type)
7721- {
7722- case ALLOCATION_TYPE_BLOCK:
7723- return m_BlockAllocation.m_Block->GetMemoryTypeIndex();
7724- case ALLOCATION_TYPE_DEDICATED:
7725- return m_DedicatedAllocation.m_MemoryTypeIndex;
7726- default:
7727- VMA_ASSERT(0);
7728- return UINT32_MAX;
7729- }
7730- }
7731-
77327742void* VmaAllocation_T::GetMappedData() const
77337743{
77347744 switch(m_Type)
@@ -11840,10 +11850,11 @@ VkResult VmaBlockVector::AllocatePage(
1184011850 freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0;
1184111851 }
1184211852
11853+ const bool canFallbackToDedicated = !IsCustomPool();
1184311854 const bool canCreateNewBlock =
1184411855 ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
1184511856 (m_Blocks.size() < m_MaxBlockCount) &&
11846- freeMemory >= size;
11857+ ( freeMemory >= size || !canFallbackToDedicated) ;
1184711858 uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;
1184811859
1184911860 // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.
@@ -11995,7 +12006,7 @@ VkResult VmaBlockVector::AllocatePage(
1199512006 }
1199612007
1199712008 size_t newBlockIndex = 0;
11998- VkResult res = newBlockSize <= freeMemory ?
12009+ VkResult res = ( newBlockSize <= freeMemory || !canFallbackToDedicated) ?
1199912010 CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
1200012011 // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
1200112012 if(!m_ExplicitBlockSize)
@@ -12007,7 +12018,7 @@ VkResult VmaBlockVector::AllocatePage(
1200712018 {
1200812019 newBlockSize = smallerNewBlockSize;
1200912020 ++newBlockSizeShift;
12010- res = newBlockSize <= freeMemory ?
12021+ res = ( newBlockSize <= freeMemory || !canFallbackToDedicated) ?
1201112022 CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
1201212023 }
1201312024 else
@@ -12162,14 +12173,14 @@ VkResult VmaBlockVector::AllocatePage(
1216212173 bestRequest.offset,
1216312174 alignment,
1216412175 size,
12176+ m_MemoryTypeIndex,
1216512177 suballocType,
1216612178 mapped,
1216712179 (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
1216812180 VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
1216912181 VMA_DEBUG_LOG(" Returned from existing block");
1217012182 (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
12171- m_hAllocator->m_Budget.m_AllocationBytes[m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex)] += size;
12172- ++m_hAllocator->m_Budget.m_OperationsSinceBudgetFetch;
12183+ m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
1217312184 if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
1217412185 {
1217512186 m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
@@ -12376,13 +12387,13 @@ VkResult VmaBlockVector::AllocateFromBlock(
1237612387 currRequest.offset,
1237712388 alignment,
1237812389 size,
12390+ m_MemoryTypeIndex,
1237912391 suballocType,
1238012392 mapped,
1238112393 (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
1238212394 VMA_HEAVY_ASSERT(pBlock->Validate());
1238312395 (*pAllocation)->SetUserData(m_hAllocator, pUserData);
12384- m_hAllocator->m_Budget.m_AllocationBytes[m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex)] += size;
12385- ++m_hAllocator->m_Budget.m_OperationsSinceBudgetFetch;
12396+ m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
1238612397 if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
1238712398 {
1238812399 m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
@@ -14987,9 +14998,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
1498714998 */
1498814999
1498915000 FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
14990- const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
14991- m_Budget.m_AllocationBytes[heapIndex] -= currAlloc->GetSize();
14992- ++m_Budget.m_OperationsSinceBudgetFetch;
15001+ m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize());
1499315002 currAlloc->SetUserData(this, VMA_NULL);
1499415003 currAlloc->Dtor();
1499515004 m_AllocationObjectAllocator.Free(currAlloc);
@@ -15041,9 +15050,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
1504115050 (*pAllocation)->Ctor(m_CurrentFrameIndex.load(), isUserDataString);
1504215051 (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
1504315052 (*pAllocation)->SetUserData(this, pUserData);
15044- const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
15045- m_Budget.m_AllocationBytes[heapIndex] += size;
15046- ++m_Budget.m_OperationsSinceBudgetFetch;
15053+ m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
1504715054 if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
1504815055 {
1504915056 FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
@@ -15311,11 +15318,8 @@ void VmaAllocator_T::FreeMemory(
1531115318 }
1531215319 }
1531315320
15314- if(allocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
15315- {
15316- m_Budget.m_AllocationBytes[MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex())] -= allocation->GetSize();
15317- ++m_Budget.m_OperationsSinceBudgetFetch;
15318- }
15321+ // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes.
15322+ m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
1531915323 allocation->SetUserData(this, VMA_NULL);
1532015324 allocation->Dtor();
1532115325 m_AllocationObjectAllocator.Free(allocation);
@@ -15748,7 +15752,7 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc
1574815752 const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
1574915753
1575015754 // HeapSizeLimit is in effect for this heap.
15751- if((m_HeapSizeLimitMask | (1u << heapIndex)) != 0)
15755+ if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0)
1575215756 {
1575315757 const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
1575415758 VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex];
@@ -15775,7 +15779,9 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc
1577515779
1577615780 if(res == VK_SUCCESS)
1577715781 {
15782+ #if VMA_MEMORY_BUDGET
1577815783 ++m_Budget.m_OperationsSinceBudgetFetch;
15784+ #endif
1577915785
1578015786 // Informative callback.
1578115787 if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
@@ -15802,9 +15808,7 @@ void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, Vk
1580215808 // VULKAN CALL vkFreeMemory.
1580315809 (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
1580415810
15805- const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType);
15806- m_Budget.m_BlockBytes[heapIndex] -= size;
15807- ++m_Budget.m_OperationsSinceBudgetFetch;
15811+ m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
1580815812}
1580915813
1581015814VkResult VmaAllocator_T::BindVulkanBuffer(
0 commit comments