Major optimization: Added VmaAllocationObjectAllocator to allocate VmaAllocation objects out of free-list allocator instead of making separate CPU heap allocations.

This commit is contained in:
Adam Sawicki 2019-01-24 18:08:24 +01:00
parent 71f9b140f0
commit a195308982

View File

@ -3718,7 +3718,7 @@ struct VmaMutexLock
{ {
VMA_CLASS_NO_COPY(VmaMutexLock) VMA_CLASS_NO_COPY(VmaMutexLock)
public: public:
VmaMutexLock(VMA_MUTEX& mutex, bool useMutex) : VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) :
m_pMutex(useMutex ? &mutex : VMA_NULL) m_pMutex(useMutex ? &mutex : VMA_NULL)
{ if(m_pMutex) { m_pMutex->Lock(); } } { if(m_pMutex) { m_pMutex->Lock(); } }
~VmaMutexLock() ~VmaMutexLock()
@ -4907,7 +4907,6 @@ enum VMA_CACHE_OPERATION { VMA_CACHE_FLUSH, VMA_CACHE_INVALIDATE };
struct VmaAllocation_T struct VmaAllocation_T
{ {
VMA_CLASS_NO_COPY(VmaAllocation_T)
private: private:
static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80; static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
@ -4924,23 +4923,29 @@ public:
ALLOCATION_TYPE_DEDICATED, ALLOCATION_TYPE_DEDICATED,
}; };
VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) : /*
m_Alignment(1), This struct cannot have constructor or destructor. It must be POD because it is
m_Size(0), allocated using VmaPoolAllocator.
m_pUserData(VMA_NULL), */
m_LastUseFrameIndex(currentFrameIndex),
m_Type((uint8_t)ALLOCATION_TYPE_NONE), void Ctor(uint32_t currentFrameIndex, bool userDataString)
m_SuballocationType((uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN),
m_MapCount(0),
m_Flags(userDataString ? (uint8_t)FLAG_USER_DATA_STRING : 0)
{ {
m_Alignment = 1;
m_Size = 0;
m_pUserData = VMA_NULL;
m_LastUseFrameIndex = currentFrameIndex;
m_Type = (uint8_t)ALLOCATION_TYPE_NONE;
m_SuballocationType = (uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN;
m_MapCount = 0;
m_Flags = userDataString ? (uint8_t)FLAG_USER_DATA_STRING : 0;
#if VMA_STATS_STRING_ENABLED #if VMA_STATS_STRING_ENABLED
m_CreationFrameIndex = currentFrameIndex; m_CreationFrameIndex = currentFrameIndex;
m_BufferImageUsage = 0; m_BufferImageUsage = 0;
#endif #endif
} }
~VmaAllocation_T() void Dtor()
{ {
VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction."); VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction.");
@ -6568,6 +6573,23 @@ private:
#endif // #if VMA_RECORDING_ENABLED #endif // #if VMA_RECORDING_ENABLED
/*
Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects.
*/
class VmaAllocationObjectAllocator
{
VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator)
public:
VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks);
VmaAllocation Allocate();
void Free(VmaAllocation hAlloc);
private:
VMA_MUTEX m_Mutex;
VmaPoolAllocator<VmaAllocation_T> m_Allocator;
};
// Main allocator object. // Main allocator object.
struct VmaAllocator_T struct VmaAllocator_T
{ {
@ -6579,6 +6601,7 @@ public:
bool m_AllocationCallbacksSpecified; bool m_AllocationCallbacksSpecified;
VkAllocationCallbacks m_AllocationCallbacks; VkAllocationCallbacks m_AllocationCallbacks;
VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks; VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
VmaAllocationObjectAllocator m_AllocationObjectAllocator;
// Number of bytes free out of limit, or VK_WHOLE_SIZE if no limit for that heap. // Number of bytes free out of limit, or VK_WHOLE_SIZE if no limit for that heap.
VkDeviceSize m_HeapSizeLimit[VK_MAX_MEMORY_HEAPS]; VkDeviceSize m_HeapSizeLimit[VK_MAX_MEMORY_HEAPS];
@ -11806,7 +11829,8 @@ VkResult VmaBlockVector::AllocatePage(
m_HasEmptyBlock = false; m_HasEmptyBlock = false;
} }
// Allocate from this pBlock. // Allocate from this pBlock.
*pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString); *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate();
(*pAllocation)->Ctor(currentFrameIndex, isUserDataString);
pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation); pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation);
(*pAllocation)->InitBlockAllocation( (*pAllocation)->InitBlockAllocation(
pBestRequestBlock, pBestRequestBlock,
@ -12008,7 +12032,8 @@ VkResult VmaBlockVector::AllocateFromBlock(
m_HasEmptyBlock = false; m_HasEmptyBlock = false;
} }
*pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString); *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate();
(*pAllocation)->Ctor(currentFrameIndex, isUserDataString);
pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation); pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation);
(*pAllocation)->InitBlockAllocation( (*pAllocation)->InitBlockAllocation(
pBlock, pBlock,
@ -14078,6 +14103,26 @@ void VmaRecorder::Flush()
#endif // #if VMA_RECORDING_ENABLED #endif // #if VMA_RECORDING_ENABLED
////////////////////////////////////////////////////////////////////////////////
// VmaAllocationObjectAllocator
VmaAllocationObjectAllocator::VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) :
m_Allocator(pAllocationCallbacks, 1024)
{
}
VmaAllocation VmaAllocationObjectAllocator::Allocate()
{
VmaMutexLock mutexLock(m_Mutex);
return m_Allocator.Alloc();
}
void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc)
{
VmaMutexLock mutexLock(m_Mutex);
m_Allocator.Free(hAlloc);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// VmaAllocator_T // VmaAllocator_T
@ -14088,6 +14133,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ? m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
*pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks), *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
m_AllocationObjectAllocator(&m_AllocationCallbacks),
m_PreferredLargeHeapBlockSize(0), m_PreferredLargeHeapBlockSize(0),
m_PhysicalDevice(pCreateInfo->physicalDevice), m_PhysicalDevice(pCreateInfo->physicalDevice),
m_CurrentFrameIndex(0), m_CurrentFrameIndex(0),
@ -14224,6 +14270,11 @@ VmaAllocator_T::~VmaAllocator_T()
for(size_t i = GetMemoryTypeCount(); i--; ) for(size_t i = GetMemoryTypeCount(); i--; )
{ {
if(m_pDedicatedAllocations[i] != VMA_NULL && !m_pDedicatedAllocations[i]->empty())
{
VMA_ASSERT(0 && "Unfreed dedicated allocations found.");
}
vma_delete(this, m_pDedicatedAllocations[i]); vma_delete(this, m_pDedicatedAllocations[i]);
vma_delete(this, m_pBlockVectors[i]); vma_delete(this, m_pBlockVectors[i]);
} }
@ -14528,7 +14579,8 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory); FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
currAlloc->SetUserData(this, VMA_NULL); currAlloc->SetUserData(this, VMA_NULL);
vma_delete(this, currAlloc); currAlloc->Dtor();
m_AllocationObjectAllocator.Free(currAlloc);
} }
memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
@ -14573,7 +14625,8 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
} }
} }
*pAllocation = vma_new(this, VmaAllocation_T)(m_CurrentFrameIndex.load(), isUserDataString); *pAllocation = m_AllocationObjectAllocator.Allocate();
(*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);
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
@ -14835,7 +14888,8 @@ void VmaAllocator_T::FreeMemory(
} }
allocation->SetUserData(this, VMA_NULL); allocation->SetUserData(this, VMA_NULL);
vma_delete(this, allocation); allocation->Dtor();
m_AllocationObjectAllocator.Free(allocation);
} }
} }
} }
@ -15214,7 +15268,8 @@ VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits)
void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation) void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
{ {
*pAllocation = vma_new(this, VmaAllocation_T)(VMA_FRAME_INDEX_LOST, false); *pAllocation = m_AllocationObjectAllocator.Allocate();
(*pAllocation)->Ctor(VMA_FRAME_INDEX_LOST, false);
(*pAllocation)->InitLost(); (*pAllocation)->InitLost();
} }