mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-22 12:20:05 +00:00
Internal improvement: Added counting total number of VkDeviceMemory blocks.
Fixed case of spamming dedicated allocations instead of bigger blocks and thus and exceeding maxMemoryAllocationCount when heap size/budget is reached or exceeded. Added debug macro VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT.
This commit is contained in:
parent
1635a1a0a3
commit
ae0b011e7a
@ -4409,6 +4409,14 @@ If providing your own implementation, you need to implement a subset of std::ato
|
|||||||
#define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
|
#define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
|
||||||
|
/*
|
||||||
|
Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount
|
||||||
|
and return error instead of leaving up to Vulkan implementation what to do in such cases.
|
||||||
|
*/
|
||||||
|
#define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef VMA_SMALL_HEAP_MAX_SIZE
|
#ifndef VMA_SMALL_HEAP_MAX_SIZE
|
||||||
/// Maximum size of a memory heap in Vulkan to consider it "small".
|
/// Maximum size of a memory heap in Vulkan to consider it "small".
|
||||||
#define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024)
|
#define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024)
|
||||||
@ -7919,6 +7927,7 @@ public:
|
|||||||
VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
|
VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
|
||||||
|
|
||||||
VmaCurrentBudgetData m_Budget;
|
VmaCurrentBudgetData m_Budget;
|
||||||
|
VMA_ATOMIC_UINT32 m_DeviceMemoryCount; // Total number of VkDeviceMemory objects.
|
||||||
|
|
||||||
VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
|
VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
|
||||||
VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo);
|
VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo);
|
||||||
@ -15729,6 +15738,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
|
|||||||
*pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
|
*pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
|
||||||
m_AllocationObjectAllocator(&m_AllocationCallbacks),
|
m_AllocationObjectAllocator(&m_AllocationCallbacks),
|
||||||
m_HeapSizeLimitMask(0),
|
m_HeapSizeLimitMask(0),
|
||||||
|
m_DeviceMemoryCount(0),
|
||||||
m_PreferredLargeHeapBlockSize(0),
|
m_PreferredLargeHeapBlockSize(0),
|
||||||
m_PhysicalDevice(pCreateInfo->physicalDevice),
|
m_PhysicalDevice(pCreateInfo->physicalDevice),
|
||||||
m_CurrentFrameIndex(0),
|
m_CurrentFrameIndex(0),
|
||||||
@ -16244,34 +16254,40 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
|
|||||||
{
|
{
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Protection against creating each allocation as dedicated when we reach or exceed heap size/budget,
|
||||||
|
// which can quickly deplete maxMemoryAllocationCount: Don't try dedicated allocations when above
|
||||||
|
// 3/4 of the maximum allocation count.
|
||||||
|
if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4)
|
||||||
|
{
|
||||||
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = AllocateDedicatedMemory(
|
||||||
|
size,
|
||||||
|
suballocType,
|
||||||
|
memTypeIndex,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
|
||||||
|
finalCreateInfo.pUserData,
|
||||||
|
finalCreateInfo.priority,
|
||||||
|
dedicatedBuffer,
|
||||||
|
dedicatedBufferUsage,
|
||||||
|
dedicatedImage,
|
||||||
|
allocationCount,
|
||||||
|
pAllocations);
|
||||||
|
if(res == VK_SUCCESS)
|
||||||
|
{
|
||||||
|
// Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
|
||||||
|
VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = AllocateDedicatedMemory(
|
// Everything failed: Return error code.
|
||||||
size,
|
VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
|
||||||
suballocType,
|
return res;
|
||||||
memTypeIndex,
|
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
|
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
|
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
|
|
||||||
finalCreateInfo.pUserData,
|
|
||||||
finalCreateInfo.priority,
|
|
||||||
dedicatedBuffer,
|
|
||||||
dedicatedBufferUsage,
|
|
||||||
dedicatedImage,
|
|
||||||
allocationCount,
|
|
||||||
pAllocations);
|
|
||||||
if(res == VK_SUCCESS)
|
|
||||||
{
|
|
||||||
// Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
|
|
||||||
VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
|
|
||||||
return VK_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Everything failed: Return error code.
|
|
||||||
VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17177,8 +17193,41 @@ void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
|
|||||||
(*pAllocation)->InitLost();
|
(*pAllocation)->InitLost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An object that increments given atomic but decrements it back in the destructor unless Commit() is called.
|
||||||
|
template<typename AtomicT>
|
||||||
|
struct AtomicTransactionalIncrement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~AtomicTransactionalIncrement()
|
||||||
|
{
|
||||||
|
if(m_Atomic)
|
||||||
|
--(*m_Atomic);
|
||||||
|
}
|
||||||
|
typename AtomicT::value_type Increment(AtomicT* atomic)
|
||||||
|
{
|
||||||
|
m_Atomic = atomic;
|
||||||
|
return m_Atomic->fetch_add(1);
|
||||||
|
}
|
||||||
|
void Commit()
|
||||||
|
{
|
||||||
|
m_Atomic = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AtomicT* m_Atomic = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
|
VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
|
||||||
{
|
{
|
||||||
|
AtomicTransactionalIncrement<VMA_ATOMIC_UINT32> deviceMemoryCountIncrement;
|
||||||
|
const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount);
|
||||||
|
#if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
|
||||||
|
if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount)
|
||||||
|
{
|
||||||
|
return VK_ERROR_TOO_MANY_OBJECTS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
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.
|
||||||
@ -17218,6 +17267,8 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc
|
|||||||
{
|
{
|
||||||
(*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData);
|
(*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceMemoryCountIncrement.Commit();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -17239,6 +17290,8 @@ void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, Vk
|
|||||||
(*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
|
(*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
|
||||||
|
|
||||||
m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
|
m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
|
||||||
|
|
||||||
|
--m_DeviceMemoryCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::BindVulkanBuffer(
|
VkResult VmaAllocator_T::BindVulkanBuffer(
|
||||||
|
Loading…
Reference in New Issue
Block a user