Multiple fixes in budget management

Including correct handling of lost allocation.
This commit is contained in:
Adam Sawicki 2019-11-18 14:47:33 +01:00
parent a63e37c656
commit 4ac8ff89c2
5 changed files with 60 additions and 48 deletions

View File

@ -66,6 +66,7 @@ typedef std::chrono::high_resolution_clock::duration duration;
extern VkPhysicalDevice g_hPhysicalDevice; extern VkPhysicalDevice g_hPhysicalDevice;
extern VkDevice g_hDevice; extern VkDevice g_hDevice;
extern VkInstance g_hVulkanInstance;
extern VmaAllocator g_hAllocator; extern VmaAllocator g_hAllocator;
extern bool g_MemoryAliasingWarningEnabled; extern bool g_MemoryAliasingWarningEnabled;

View File

@ -2000,6 +2000,7 @@ void TestHeapSizeLimit()
VmaAllocatorCreateInfo allocatorCreateInfo = {}; VmaAllocatorCreateInfo allocatorCreateInfo = {};
allocatorCreateInfo.physicalDevice = g_hPhysicalDevice; allocatorCreateInfo.physicalDevice = g_hPhysicalDevice;
allocatorCreateInfo.device = g_hDevice; allocatorCreateInfo.device = g_hDevice;
allocatorCreateInfo.instance = g_hVulkanInstance;
allocatorCreateInfo.pHeapSizeLimit = heapSizeLimit; allocatorCreateInfo.pHeapSizeLimit = heapSizeLimit;
VmaAllocator hAllocator; VmaAllocator hAllocator;
@ -2016,8 +2017,8 @@ void TestHeapSizeLimit()
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufCreateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufCreateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
// 1. Allocate two blocks of Own Memory, half the size of BLOCK_SIZE. // 1. Allocate two blocks of dedicated memory, half the size of BLOCK_SIZE.
VmaAllocationInfo ownAllocInfo; VmaAllocationInfo dedicatedAllocInfo;
{ {
VmaAllocationCreateInfo allocCreateInfo = {}; VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
@ -2028,7 +2029,7 @@ void TestHeapSizeLimit()
for(size_t i = 0; i < 2; ++i) for(size_t i = 0; i < 2; ++i)
{ {
Item item; Item item;
res = vmaCreateBuffer(hAllocator, &bufCreateInfo, &allocCreateInfo, &item.hBuf, &item.hAlloc, &ownAllocInfo); res = vmaCreateBuffer(hAllocator, &bufCreateInfo, &allocCreateInfo, &item.hBuf, &item.hAlloc, &dedicatedAllocInfo);
TEST(res == VK_SUCCESS); TEST(res == VK_SUCCESS);
items.push_back(item); items.push_back(item);
} }
@ -2036,7 +2037,7 @@ void TestHeapSizeLimit()
// Create pool to make sure allocations must be out of this memory type. // Create pool to make sure allocations must be out of this memory type.
VmaPoolCreateInfo poolCreateInfo = {}; VmaPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.memoryTypeIndex = ownAllocInfo.memoryType; poolCreateInfo.memoryTypeIndex = dedicatedAllocInfo.memoryType;
poolCreateInfo.blockSize = BLOCK_SIZE; poolCreateInfo.blockSize = BLOCK_SIZE;
VmaPool hPool; VmaPool hPool;
@ -3873,8 +3874,6 @@ static void TestBudget()
{ {
wprintf(L"Testing budget...\n"); wprintf(L"Testing budget...\n");
uint32_t memTypeIndex = UINT32_MAX;
static const VkDeviceSize BUF_SIZE = 100ull * 1024 * 1024; static const VkDeviceSize BUF_SIZE = 100ull * 1024 * 1024;
static const uint32_t BUF_COUNT = 4; static const uint32_t BUF_COUNT = 4;
@ -3885,6 +3884,11 @@ static void TestBudget()
VmaBudget budgetBeg[VK_MAX_MEMORY_HEAPS] = {}; VmaBudget budgetBeg[VK_MAX_MEMORY_HEAPS] = {};
vmaGetBudget(g_hAllocator, budgetBeg); vmaGetBudget(g_hAllocator, budgetBeg);
for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
{
TEST(budgetBeg[i].allocationBytes <= budgetBeg[i].blockBytes);
}
VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufInfo.size = BUF_SIZE; bufInfo.size = BUF_SIZE;
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
@ -5234,7 +5238,7 @@ void Test()
//PerformCustomPoolTest(file); //PerformCustomPoolTest(file);
fclose(file); fclose(file);
wprintf(L"Done.\n"); wprintf(L"Done.\n");
} }

View File

@ -49,6 +49,7 @@ include all public interface declarations. Example:
//#define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY 256 //#define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY 256
//#define VMA_USE_STL_SHARED_MUTEX 0 //#define VMA_USE_STL_SHARED_MUTEX 0
//#define VMA_DEBUG_GLOBAL_MUTEX 1 //#define VMA_DEBUG_GLOBAL_MUTEX 1
//#define VMA_MEMORY_BUDGET 0
/* /*
#define VMA_DEBUG_LOG(format, ...) do { \ #define VMA_DEBUG_LOG(format, ...) do { \
printf(format, __VA_ARGS__); \ printf(format, __VA_ARGS__); \

View File

@ -43,6 +43,7 @@ static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = true;
VkPhysicalDevice g_hPhysicalDevice; VkPhysicalDevice g_hPhysicalDevice;
VkDevice g_hDevice; VkDevice g_hDevice;
VmaAllocator g_hAllocator; VmaAllocator g_hAllocator;
VkInstance g_hVulkanInstance;
bool g_MemoryAliasingWarningEnabled = true; bool g_MemoryAliasingWarningEnabled = true;
static bool g_EnableValidationLayer = true; static bool g_EnableValidationLayer = true;
@ -56,7 +57,6 @@ bool g_SparseBindingEnabled = false;
static HINSTANCE g_hAppInstance; static HINSTANCE g_hAppInstance;
static HWND g_hWnd; static HWND g_hWnd;
static LONG g_SizeX = 1280, g_SizeY = 720; static LONG g_SizeX = 1280, g_SizeY = 720;
static VkInstance g_hVulkanInstance;
static VkSurfaceKHR g_hSurface; static VkSurfaceKHR g_hSurface;
static VkQueue g_hPresentQueue; static VkQueue g_hPresentQueue;
static VkSurfaceFormatKHR g_SurfaceFormat; static VkSurfaceFormatKHR g_SurfaceFormat;
@ -1369,10 +1369,12 @@ static void InitializeApplication()
{ {
allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT; allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
} }
#if !defined(VMA_MEMORY_BUDGET) || VMA_MEMORY_BUDGET == 1
if(VK_EXT_memory_budget_enabled && VK_KHR_get_physical_device_properties2_enabled) if(VK_EXT_memory_budget_enabled && VK_KHR_get_physical_device_properties2_enabled)
{ {
allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
} }
#endif
if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS) if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
{ {

View File

@ -2154,9 +2154,12 @@ typedef struct VmaBudget
/** \brief Sum size of all allocations created in particular heap, in bytes. /** \brief Sum size of all allocations created in particular heap, in bytes.
Always less or equal than `blockBytes`. Usually less or equal than `blockBytes`.
Difference `blockBytes - allocationBytes` is the amount of memory allocated but unused - Difference `blockBytes - allocationBytes` is the amount of memory allocated but unused -
available for new allocations or wasted due to fragmentation. available for new allocations or wasted due to fragmentation.
It might be greater than `blockBytes` if there are some allocations in lost state, as they account
to this value as well.
*/ */
VkDeviceSize allocationBytes; VkDeviceSize allocationBytes;
@ -5284,6 +5287,7 @@ public:
{ {
m_Alignment = 1; m_Alignment = 1;
m_Size = 0; m_Size = 0;
m_MemoryTypeIndex = 0;
m_pUserData = VMA_NULL; m_pUserData = VMA_NULL;
m_LastUseFrameIndex = currentFrameIndex; m_LastUseFrameIndex = currentFrameIndex;
m_Type = (uint8_t)ALLOCATION_TYPE_NONE; m_Type = (uint8_t)ALLOCATION_TYPE_NONE;
@ -5310,6 +5314,7 @@ public:
VkDeviceSize offset, VkDeviceSize offset,
VkDeviceSize alignment, VkDeviceSize alignment,
VkDeviceSize size, VkDeviceSize size,
uint32_t memoryTypeIndex,
VmaSuballocationType suballocationType, VmaSuballocationType suballocationType,
bool mapped, bool mapped,
bool canBecomeLost) bool canBecomeLost)
@ -5319,6 +5324,7 @@ public:
m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
m_Alignment = alignment; m_Alignment = alignment;
m_Size = size; m_Size = size;
m_MemoryTypeIndex = memoryTypeIndex;
m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0; m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
m_SuballocationType = (uint8_t)suballocationType; m_SuballocationType = (uint8_t)suballocationType;
m_BlockAllocation.m_Block = block; m_BlockAllocation.m_Block = block;
@ -5331,6 +5337,7 @@ public:
VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST); VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
m_MemoryTypeIndex = 0;
m_BlockAllocation.m_Block = VMA_NULL; m_BlockAllocation.m_Block = VMA_NULL;
m_BlockAllocation.m_Offset = 0; m_BlockAllocation.m_Offset = 0;
m_BlockAllocation.m_CanBecomeLost = true; m_BlockAllocation.m_CanBecomeLost = true;
@ -5356,9 +5363,9 @@ public:
m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED; m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
m_Alignment = 0; m_Alignment = 0;
m_Size = size; m_Size = size;
m_MemoryTypeIndex = memoryTypeIndex;
m_SuballocationType = (uint8_t)suballocationType; m_SuballocationType = (uint8_t)suballocationType;
m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0; m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
m_DedicatedAllocation.m_MemoryTypeIndex = memoryTypeIndex;
m_DedicatedAllocation.m_hMemory = hMemory; m_DedicatedAllocation.m_hMemory = hMemory;
m_DedicatedAllocation.m_pMappedData = pMappedData; m_DedicatedAllocation.m_pMappedData = pMappedData;
} }
@ -5378,7 +5385,7 @@ public:
} }
VkDeviceSize GetOffset() const; VkDeviceSize GetOffset() const;
VkDeviceMemory GetMemory() const; VkDeviceMemory GetMemory() const;
uint32_t GetMemoryTypeIndex() const; uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; } bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
void* GetMappedData() const; void* GetMappedData() const;
bool CanBecomeLost() const; bool CanBecomeLost() const;
@ -5437,6 +5444,7 @@ private:
VkDeviceSize m_Size; VkDeviceSize m_Size;
void* m_pUserData; void* m_pUserData;
VMA_ATOMIC_UINT32 m_LastUseFrameIndex; VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
uint32_t m_MemoryTypeIndex;
uint8_t m_Type; // ALLOCATION_TYPE uint8_t m_Type; // ALLOCATION_TYPE
uint8_t m_SuballocationType; // VmaSuballocationType uint8_t m_SuballocationType; // VmaSuballocationType
// Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT. // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
@ -5455,7 +5463,6 @@ private:
// Allocation for an object that has its own private VkDeviceMemory. // Allocation for an object that has its own private VkDeviceMemory.
struct DedicatedAllocation struct DedicatedAllocation
{ {
uint32_t m_MemoryTypeIndex;
VkDeviceMemory m_hMemory; VkDeviceMemory m_hMemory;
void* m_pMappedData; // Not null means memory is mapped. void* m_pMappedData; // Not null means memory is mapped.
}; };
@ -6964,6 +6971,23 @@ struct VmaCurrentBudgetData
#if VMA_MEMORY_BUDGET #if VMA_MEMORY_BUDGET
m_OperationsSinceBudgetFetch = 0; m_OperationsSinceBudgetFetch = 0;
#endif
}
void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
{
m_AllocationBytes[heapIndex] += allocationSize;
#if VMA_MEMORY_BUDGET
++m_OperationsSinceBudgetFetch;
#endif
}
void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
{
VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME
m_AllocationBytes[heapIndex] -= allocationSize;
#if VMA_MEMORY_BUDGET
++m_OperationsSinceBudgetFetch;
#endif #endif
} }
}; };
@ -7715,20 +7739,6 @@ VkDeviceMemory VmaAllocation_T::GetMemory() const
} }
} }
uint32_t VmaAllocation_T::GetMemoryTypeIndex() const
{
switch(m_Type)
{
case ALLOCATION_TYPE_BLOCK:
return m_BlockAllocation.m_Block->GetMemoryTypeIndex();
case ALLOCATION_TYPE_DEDICATED:
return m_DedicatedAllocation.m_MemoryTypeIndex;
default:
VMA_ASSERT(0);
return UINT32_MAX;
}
}
void* VmaAllocation_T::GetMappedData() const void* VmaAllocation_T::GetMappedData() const
{ {
switch(m_Type) switch(m_Type)
@ -11840,10 +11850,11 @@ VkResult VmaBlockVector::AllocatePage(
freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0; freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0;
} }
const bool canFallbackToDedicated = !IsCustomPool();
const bool canCreateNewBlock = const bool canCreateNewBlock =
((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) && ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
(m_Blocks.size() < m_MaxBlockCount) && (m_Blocks.size() < m_MaxBlockCount) &&
freeMemory >= size; (freeMemory >= size || !canFallbackToDedicated);
uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK; uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;
// If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer. // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.
@ -11995,7 +12006,7 @@ VkResult VmaBlockVector::AllocatePage(
} }
size_t newBlockIndex = 0; size_t newBlockIndex = 0;
VkResult res = newBlockSize <= freeMemory ? VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
// Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize. // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
if(!m_ExplicitBlockSize) if(!m_ExplicitBlockSize)
@ -12007,7 +12018,7 @@ VkResult VmaBlockVector::AllocatePage(
{ {
newBlockSize = smallerNewBlockSize; newBlockSize = smallerNewBlockSize;
++newBlockSizeShift; ++newBlockSizeShift;
res = newBlockSize <= freeMemory ? res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
} }
else else
@ -12162,14 +12173,14 @@ VkResult VmaBlockVector::AllocatePage(
bestRequest.offset, bestRequest.offset,
alignment, alignment,
size, size,
m_MemoryTypeIndex,
suballocType, suballocType,
mapped, mapped,
(createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
VMA_HEAVY_ASSERT(pBestRequestBlock->Validate()); VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
VMA_DEBUG_LOG(" Returned from existing block"); VMA_DEBUG_LOG(" Returned from existing block");
(*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData); (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
m_hAllocator->m_Budget.m_AllocationBytes[m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex)] += size; m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
++m_hAllocator->m_Budget.m_OperationsSinceBudgetFetch;
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
{ {
m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
@ -12376,13 +12387,13 @@ VkResult VmaBlockVector::AllocateFromBlock(
currRequest.offset, currRequest.offset,
alignment, alignment,
size, size,
m_MemoryTypeIndex,
suballocType, suballocType,
mapped, mapped,
(allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
VMA_HEAVY_ASSERT(pBlock->Validate()); VMA_HEAVY_ASSERT(pBlock->Validate());
(*pAllocation)->SetUserData(m_hAllocator, pUserData); (*pAllocation)->SetUserData(m_hAllocator, pUserData);
m_hAllocator->m_Budget.m_AllocationBytes[m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex)] += size; m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
++m_hAllocator->m_Budget.m_OperationsSinceBudgetFetch;
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
{ {
m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
@ -14987,9 +14998,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
*/ */
FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory); FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize());
m_Budget.m_AllocationBytes[heapIndex] -= currAlloc->GetSize();
++m_Budget.m_OperationsSinceBudgetFetch;
currAlloc->SetUserData(this, VMA_NULL); currAlloc->SetUserData(this, VMA_NULL);
currAlloc->Dtor(); currAlloc->Dtor();
m_AllocationObjectAllocator.Free(currAlloc); m_AllocationObjectAllocator.Free(currAlloc);
@ -15041,9 +15050,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
(*pAllocation)->Ctor(m_CurrentFrameIndex.load(), isUserDataString); (*pAllocation)->Ctor(m_CurrentFrameIndex.load(), isUserDataString);
(*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size); (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
(*pAllocation)->SetUserData(this, pUserData); (*pAllocation)->SetUserData(this, pUserData);
const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
m_Budget.m_AllocationBytes[heapIndex] += size;
++m_Budget.m_OperationsSinceBudgetFetch;
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
{ {
FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
@ -15311,11 +15318,8 @@ void VmaAllocator_T::FreeMemory(
} }
} }
if(allocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST) // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes.
{ m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
m_Budget.m_AllocationBytes[MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex())] -= allocation->GetSize();
++m_Budget.m_OperationsSinceBudgetFetch;
}
allocation->SetUserData(this, VMA_NULL); allocation->SetUserData(this, VMA_NULL);
allocation->Dtor(); allocation->Dtor();
m_AllocationObjectAllocator.Free(allocation); m_AllocationObjectAllocator.Free(allocation);
@ -15748,7 +15752,7 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc
const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
// HeapSizeLimit is in effect for this heap. // HeapSizeLimit is in effect for this heap.
if((m_HeapSizeLimitMask | (1u << heapIndex)) != 0) if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0)
{ {
const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex]; VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex];
@ -15775,7 +15779,9 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc
if(res == VK_SUCCESS) if(res == VK_SUCCESS)
{ {
#if VMA_MEMORY_BUDGET
++m_Budget.m_OperationsSinceBudgetFetch; ++m_Budget.m_OperationsSinceBudgetFetch;
#endif
// Informative callback. // Informative callback.
if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
@ -15802,9 +15808,7 @@ void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, Vk
// VULKAN CALL vkFreeMemory. // VULKAN CALL vkFreeMemory.
(*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks()); (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType); m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
m_Budget.m_BlockBytes[heapIndex] -= size;
++m_Budget.m_OperationsSinceBudgetFetch;
} }
VkResult VmaAllocator_T::BindVulkanBuffer( VkResult VmaAllocator_T::BindVulkanBuffer(