mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2025-05-15 01:08:31 +00:00
Added support for dedicated allocations in custom pools
A major refactoring. JSON format changed!
This commit is contained in:
parent
a8c1543723
commit
e9c083b4d2
2 changed files with 647 additions and 558 deletions
|
@ -2908,6 +2908,8 @@ static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x000000
|
||||||
static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000;
|
static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000;
|
||||||
static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
|
static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
|
||||||
static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
|
static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
|
||||||
|
static const uint32_t VMA_VENDOR_ID_AMD = 4098;
|
||||||
|
|
||||||
|
|
||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
// Correspond to values of enum VmaSuballocationType.
|
// Correspond to values of enum VmaSuballocationType.
|
||||||
|
@ -2961,6 +2963,9 @@ struct VmaMutexLock;
|
||||||
struct VmaMutexLockRead;
|
struct VmaMutexLockRead;
|
||||||
struct VmaMutexLockWrite;
|
struct VmaMutexLockWrite;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct AtomicTransactionalIncrement;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct VmaStlAllocator;
|
struct VmaStlAllocator;
|
||||||
|
|
||||||
|
@ -3630,6 +3635,32 @@ private:
|
||||||
#endif
|
#endif
|
||||||
#endif // _VMA_MUTEX_LOCK
|
#endif // _VMA_MUTEX_LOCK
|
||||||
|
|
||||||
|
#ifndef _VMA_ATOMIC_TRANSACTIONAL_INCREMENT
|
||||||
|
// An object that increments given atomic but decrements it back in the destructor unless Commit() is called.
|
||||||
|
template<typename T>
|
||||||
|
struct AtomicTransactionalIncrement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::atomic<T> AtomicT;
|
||||||
|
|
||||||
|
~AtomicTransactionalIncrement()
|
||||||
|
{
|
||||||
|
if(m_Atomic)
|
||||||
|
--(*m_Atomic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commit() { m_Atomic = nullptr; }
|
||||||
|
T Increment(AtomicT* atomic)
|
||||||
|
{
|
||||||
|
m_Atomic = atomic;
|
||||||
|
return m_Atomic->fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AtomicT* m_Atomic = nullptr;
|
||||||
|
};
|
||||||
|
#endif // _VMA_ATOMIC_TRANSACTIONAL_INCREMENT
|
||||||
|
|
||||||
#ifndef _VMA_STL_ALLOCATOR
|
#ifndef _VMA_STL_ALLOCATOR
|
||||||
// STL-compatible allocator.
|
// STL-compatible allocator.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -5508,6 +5539,7 @@ public:
|
||||||
void InitLost();
|
void InitLost();
|
||||||
// pMappedData not null means allocation is created with MAPPED flag.
|
// pMappedData not null means allocation is created with MAPPED flag.
|
||||||
void InitDedicatedAllocation(
|
void InitDedicatedAllocation(
|
||||||
|
VmaPool hParentPool,
|
||||||
uint32_t memoryTypeIndex,
|
uint32_t memoryTypeIndex,
|
||||||
VkDeviceMemory hMemory,
|
VkDeviceMemory hMemory,
|
||||||
VmaSuballocationType suballocationType,
|
VmaSuballocationType suballocationType,
|
||||||
|
@ -5531,6 +5563,7 @@ public:
|
||||||
void ChangeBlockAllocation(VmaAllocator hAllocator, VmaDeviceMemoryBlock* block, VkDeviceSize offset);
|
void ChangeBlockAllocation(VmaAllocator hAllocator, VmaDeviceMemoryBlock* block, VkDeviceSize offset);
|
||||||
void ChangeOffset(VkDeviceSize newOffset);
|
void ChangeOffset(VkDeviceSize newOffset);
|
||||||
VkDeviceSize GetOffset() const;
|
VkDeviceSize GetOffset() const;
|
||||||
|
VmaPool GetParentPool() const;
|
||||||
VkDeviceMemory GetMemory() const;
|
VkDeviceMemory GetMemory() const;
|
||||||
void* GetMappedData() const;
|
void* GetMappedData() const;
|
||||||
bool CanBecomeLost() const;
|
bool CanBecomeLost() const;
|
||||||
|
@ -5570,6 +5603,7 @@ 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
|
||||||
{
|
{
|
||||||
|
VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
|
||||||
VkDeviceMemory m_hMemory;
|
VkDeviceMemory m_hMemory;
|
||||||
void* m_pMappedData; // Not null means memory is mapped.
|
void* m_pMappedData; // Not null means memory is mapped.
|
||||||
VmaAllocation_T* m_Prev;
|
VmaAllocation_T* m_Prev;
|
||||||
|
@ -5644,7 +5678,7 @@ public:
|
||||||
|
|
||||||
void Init(bool useMutex) { m_UseMutex = useMutex; }
|
void Init(bool useMutex) { m_UseMutex = useMutex; }
|
||||||
|
|
||||||
void CalculateStats(VmaStats* stats, uint32_t memTypeIndex, uint32_t memHeapIndex);
|
void AddStats(VmaStats* stats, uint32_t memTypeIndex, uint32_t memHeapIndex);
|
||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
// Writes JSON array with the list of allocations.
|
// Writes JSON array with the list of allocations.
|
||||||
void BuildStatsString(VmaJsonWriter& json);
|
void BuildStatsString(VmaJsonWriter& json);
|
||||||
|
@ -5672,9 +5706,9 @@ VmaDedicatedAllocationList::~VmaDedicatedAllocationList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VmaDedicatedAllocationList::CalculateStats(VmaStats* stats, uint32_t memTypeIndex, uint32_t memHeapIndex)
|
void VmaDedicatedAllocationList::AddStats(VmaStats* stats, uint32_t memTypeIndex, uint32_t memHeapIndex)
|
||||||
{
|
{
|
||||||
VmaMutexLockWrite(m_Mutex, m_UseMutex);
|
VmaMutexLockRead(m_Mutex, m_UseMutex);
|
||||||
for (VmaAllocation alloc = m_AllocationList.Front();
|
for (VmaAllocation alloc = m_AllocationList.Front();
|
||||||
alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc))
|
alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc))
|
||||||
{
|
{
|
||||||
|
@ -5689,7 +5723,7 @@ void VmaDedicatedAllocationList::CalculateStats(VmaStats* stats, uint32_t memTyp
|
||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
void VmaDedicatedAllocationList::BuildStatsString(VmaJsonWriter& json)
|
void VmaDedicatedAllocationList::BuildStatsString(VmaJsonWriter& json)
|
||||||
{
|
{
|
||||||
VmaMutexLockWrite(m_Mutex, m_UseMutex);
|
VmaMutexLockRead(m_Mutex, m_UseMutex);
|
||||||
json.BeginArray();
|
json.BeginArray();
|
||||||
for (VmaAllocation alloc = m_AllocationList.Front();
|
for (VmaAllocation alloc = m_AllocationList.Front();
|
||||||
alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc))
|
alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc))
|
||||||
|
@ -5704,7 +5738,7 @@ void VmaDedicatedAllocationList::BuildStatsString(VmaJsonWriter& json)
|
||||||
|
|
||||||
bool VmaDedicatedAllocationList::IsEmpty()
|
bool VmaDedicatedAllocationList::IsEmpty()
|
||||||
{
|
{
|
||||||
VmaMutexLockWrite(m_Mutex, m_UseMutex);
|
VmaMutexLockRead(m_Mutex, m_UseMutex);
|
||||||
return m_AllocationList.IsEmpty();
|
return m_AllocationList.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9829,6 +9863,9 @@ public:
|
||||||
VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
|
VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
|
||||||
uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
|
uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
|
||||||
uint32_t GetAlgorithm() const { return m_Algorithm; }
|
uint32_t GetAlgorithm() const { return m_Algorithm; }
|
||||||
|
bool HasExplicitBlockSize() const { return m_ExplicitBlockSize; }
|
||||||
|
float GetPriority() const { return m_Priority; }
|
||||||
|
void* const GetAllocationNextPtr() const { return m_pMemoryAllocateNext; }
|
||||||
|
|
||||||
VkResult CreateMinBlocks();
|
VkResult CreateMinBlocks();
|
||||||
void GetPoolStats(VmaPoolStats* pStats);
|
void GetPoolStats(VmaPoolStats* pStats);
|
||||||
|
@ -10274,7 +10311,7 @@ struct VmaPool_T
|
||||||
VMA_CLASS_NO_COPY(VmaPool_T)
|
VMA_CLASS_NO_COPY(VmaPool_T)
|
||||||
public:
|
public:
|
||||||
VmaBlockVector m_BlockVector;
|
VmaBlockVector m_BlockVector;
|
||||||
//VmaDedicatedAllocationList m_DedicatedAllocations;
|
VmaDedicatedAllocationList m_DedicatedAllocations;
|
||||||
|
|
||||||
VmaPool_T(
|
VmaPool_T(
|
||||||
VmaAllocator hAllocator,
|
VmaAllocator hAllocator,
|
||||||
|
@ -10916,20 +10953,24 @@ private:
|
||||||
VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
|
VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
|
||||||
|
|
||||||
VkResult AllocateMemoryOfType(
|
VkResult AllocateMemoryOfType(
|
||||||
|
VmaPool pool,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VkDeviceSize alignment,
|
VkDeviceSize alignment,
|
||||||
bool dedicatedAllocation,
|
bool dedicatedPreferred,
|
||||||
VkBuffer dedicatedBuffer,
|
VkBuffer dedicatedBuffer,
|
||||||
VkBufferUsageFlags dedicatedBufferUsage,
|
VkBufferUsageFlags dedicatedBufferUsage,
|
||||||
VkImage dedicatedImage,
|
VkImage dedicatedImage,
|
||||||
const VmaAllocationCreateInfo& createInfo,
|
const VmaAllocationCreateInfo& createInfo,
|
||||||
uint32_t memTypeIndex,
|
uint32_t memTypeIndex,
|
||||||
VmaSuballocationType suballocType,
|
VmaSuballocationType suballocType,
|
||||||
|
VmaDedicatedAllocationList& dedicatedAllocations,
|
||||||
|
VmaBlockVector& blockVector,
|
||||||
size_t allocationCount,
|
size_t allocationCount,
|
||||||
VmaAllocation* pAllocations);
|
VmaAllocation* pAllocations);
|
||||||
|
|
||||||
// Helper function only to be used inside AllocateDedicatedMemory.
|
// Helper function only to be used inside AllocateDedicatedMemory.
|
||||||
VkResult AllocateDedicatedMemoryPage(
|
VkResult AllocateDedicatedMemoryPage(
|
||||||
|
VmaPool pool,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VmaSuballocationType suballocType,
|
VmaSuballocationType suballocType,
|
||||||
uint32_t memTypeIndex,
|
uint32_t memTypeIndex,
|
||||||
|
@ -10941,10 +10982,11 @@ private:
|
||||||
|
|
||||||
// Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
|
// Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
|
||||||
VkResult AllocateDedicatedMemory(
|
VkResult AllocateDedicatedMemory(
|
||||||
|
VmaPool pool,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VmaSuballocationType suballocType,
|
VmaSuballocationType suballocType,
|
||||||
|
VmaDedicatedAllocationList& dedicatedAllocations,
|
||||||
uint32_t memTypeIndex,
|
uint32_t memTypeIndex,
|
||||||
bool withinBudget,
|
|
||||||
bool map,
|
bool map,
|
||||||
bool isUserDataString,
|
bool isUserDataString,
|
||||||
bool canAliasMemory,
|
bool canAliasMemory,
|
||||||
|
@ -10954,16 +10996,26 @@ private:
|
||||||
VkBufferUsageFlags dedicatedBufferUsage,
|
VkBufferUsageFlags dedicatedBufferUsage,
|
||||||
VkImage dedicatedImage,
|
VkImage dedicatedImage,
|
||||||
size_t allocationCount,
|
size_t allocationCount,
|
||||||
VmaAllocation* pAllocations);
|
VmaAllocation* pAllocations,
|
||||||
|
const void* pNextChain = nullptr);
|
||||||
|
|
||||||
void FreeDedicatedMemory(const VmaAllocation allocation);
|
void FreeDedicatedMemory(const VmaAllocation allocation);
|
||||||
|
|
||||||
|
VkResult CalcMemTypeParams(
|
||||||
|
VmaAllocationCreateInfo& outCreateInfo,
|
||||||
|
uint32_t memTypeIndex,
|
||||||
|
VkDeviceSize size,
|
||||||
|
size_t allocationCount);
|
||||||
|
VkResult CalcAllocationParams(
|
||||||
|
VmaAllocationCreateInfo& outCreateInfo,
|
||||||
|
bool dedicatedRequired,
|
||||||
|
bool dedicatedPreferred);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculates and returns bit mask of memory types that can support defragmentation
|
Calculates and returns bit mask of memory types that can support defragmentation
|
||||||
on GPU as they support creation of required buffer for copy operations.
|
on GPU as they support creation of required buffer for copy operations.
|
||||||
*/
|
*/
|
||||||
uint32_t CalculateGpuDefragmentationMemoryTypeBits() const;
|
uint32_t CalculateGpuDefragmentationMemoryTypeBits() const;
|
||||||
|
|
||||||
uint32_t CalculateGlobalMemoryTypeBits() const;
|
uint32_t CalculateGlobalMemoryTypeBits() const;
|
||||||
|
|
||||||
bool GetFlushOrInvalidateRange(
|
bool GetFlushOrInvalidateRange(
|
||||||
|
@ -11313,6 +11365,7 @@ void VmaAllocation_T::InitLost()
|
||||||
}
|
}
|
||||||
|
|
||||||
void VmaAllocation_T::InitDedicatedAllocation(
|
void VmaAllocation_T::InitDedicatedAllocation(
|
||||||
|
VmaPool hParentPool,
|
||||||
uint32_t memoryTypeIndex,
|
uint32_t memoryTypeIndex,
|
||||||
VkDeviceMemory hMemory,
|
VkDeviceMemory hMemory,
|
||||||
VmaSuballocationType suballocationType,
|
VmaSuballocationType suballocationType,
|
||||||
|
@ -11327,6 +11380,7 @@ void VmaAllocation_T::InitDedicatedAllocation(
|
||||||
m_MemoryTypeIndex = memoryTypeIndex;
|
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_hParentPool = hParentPool;
|
||||||
m_DedicatedAllocation.m_hMemory = hMemory;
|
m_DedicatedAllocation.m_hMemory = hMemory;
|
||||||
m_DedicatedAllocation.m_pMappedData = pMappedData;
|
m_DedicatedAllocation.m_pMappedData = pMappedData;
|
||||||
m_DedicatedAllocation.m_Prev = VMA_NULL;
|
m_DedicatedAllocation.m_Prev = VMA_NULL;
|
||||||
|
@ -11394,6 +11448,20 @@ VkDeviceSize VmaAllocation_T::GetOffset() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VmaPool VmaAllocation_T::GetParentPool() const
|
||||||
|
{
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case ALLOCATION_TYPE_BLOCK:
|
||||||
|
return m_BlockAllocation.m_Block->GetParentPool();
|
||||||
|
case ALLOCATION_TYPE_DEDICATED:
|
||||||
|
return m_DedicatedAllocation.m_hParentPool;
|
||||||
|
default:
|
||||||
|
VMA_ASSERT(0);
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkDeviceMemory VmaAllocation_T::GetMemory() const
|
VkDeviceMemory VmaAllocation_T::GetMemory() const
|
||||||
{
|
{
|
||||||
switch (m_Type)
|
switch (m_Type)
|
||||||
|
@ -12648,8 +12716,6 @@ void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
|
||||||
{
|
{
|
||||||
VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
|
VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
|
||||||
|
|
||||||
json.BeginObject();
|
|
||||||
|
|
||||||
if (IsCustomPool())
|
if (IsCustomPool())
|
||||||
{
|
{
|
||||||
const char* poolName = m_hParentPool->GetName();
|
const char* poolName = m_hParentPool->GetName();
|
||||||
|
@ -12710,8 +12776,6 @@ void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
|
||||||
m_Blocks[i]->m_pMetadata->PrintDetailedMap(json);
|
m_Blocks[i]->m_pMetadata->PrintDetailedMap(json);
|
||||||
}
|
}
|
||||||
json.EndObject();
|
json.EndObject();
|
||||||
|
|
||||||
json.EndObject();
|
|
||||||
}
|
}
|
||||||
#endif // VMA_STATS_STRING_ENABLED
|
#endif // VMA_STATS_STRING_ENABLED
|
||||||
|
|
||||||
|
@ -15353,15 +15417,18 @@ VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::AllocateMemoryOfType(
|
VkResult VmaAllocator_T::AllocateMemoryOfType(
|
||||||
|
VmaPool pool,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VkDeviceSize alignment,
|
VkDeviceSize alignment,
|
||||||
bool dedicatedAllocation,
|
bool dedicatedPreferred,
|
||||||
VkBuffer dedicatedBuffer,
|
VkBuffer dedicatedBuffer,
|
||||||
VkBufferUsageFlags dedicatedBufferUsage,
|
VkBufferUsageFlags dedicatedBufferUsage,
|
||||||
VkImage dedicatedImage,
|
VkImage dedicatedImage,
|
||||||
const VmaAllocationCreateInfo& createInfo,
|
const VmaAllocationCreateInfo& createInfo,
|
||||||
uint32_t memTypeIndex,
|
uint32_t memTypeIndex,
|
||||||
VmaSuballocationType suballocType,
|
VmaSuballocationType suballocType,
|
||||||
|
VmaDedicatedAllocationList& dedicatedAllocations,
|
||||||
|
VmaBlockVector& blockVector,
|
||||||
size_t allocationCount,
|
size_t allocationCount,
|
||||||
VmaAllocation* pAllocations)
|
VmaAllocation* pAllocations)
|
||||||
{
|
{
|
||||||
|
@ -15369,95 +15436,22 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
|
||||||
VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size);
|
VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size);
|
||||||
|
|
||||||
VmaAllocationCreateInfo finalCreateInfo = createInfo;
|
VmaAllocationCreateInfo finalCreateInfo = createInfo;
|
||||||
|
VkResult res = CalcMemTypeParams(
|
||||||
// If memory type is not HOST_VISIBLE, disable MAPPED.
|
finalCreateInfo,
|
||||||
if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
|
memTypeIndex,
|
||||||
(m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
|
size,
|
||||||
{
|
allocationCount);
|
||||||
finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
if(res != VK_SUCCESS)
|
||||||
}
|
return res;
|
||||||
// If memory is lazily allocated, it should be always dedicated.
|
|
||||||
if(finalCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED)
|
|
||||||
{
|
|
||||||
finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex];
|
|
||||||
VMA_ASSERT(blockVector && "Trying to use unsupported memory type!");
|
|
||||||
|
|
||||||
const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
|
|
||||||
bool preferDedicatedMemory =
|
|
||||||
VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
|
|
||||||
dedicatedAllocation ||
|
|
||||||
// Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
|
|
||||||
size > preferredBlockSize / 2;
|
|
||||||
|
|
||||||
if(preferDedicatedMemory &&
|
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
|
|
||||||
finalCreateInfo.pool == VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
|
if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
|
||||||
{
|
{
|
||||||
if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
|
return AllocateDedicatedMemory(
|
||||||
{
|
pool,
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 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.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0,
|
|
||||||
finalCreateInfo.pUserData,
|
|
||||||
finalCreateInfo.priority,
|
|
||||||
dedicatedBuffer,
|
|
||||||
dedicatedBufferUsage,
|
|
||||||
dedicatedImage,
|
|
||||||
allocationCount,
|
|
||||||
pAllocations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VkResult res = blockVector->Allocate(
|
|
||||||
m_CurrentFrameIndex.load(),
|
|
||||||
size,
|
|
||||||
alignment,
|
|
||||||
finalCreateInfo,
|
|
||||||
suballocType,
|
|
||||||
allocationCount,
|
|
||||||
pAllocations);
|
|
||||||
if(res == VK_SUCCESS)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Try dedicated memory.
|
|
||||||
if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
|
|
||||||
{
|
|
||||||
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,
|
size,
|
||||||
suballocType,
|
suballocType,
|
||||||
|
dedicatedAllocations,
|
||||||
memTypeIndex,
|
memTypeIndex,
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
|
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
|
||||||
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0,
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0,
|
||||||
|
@ -15467,27 +15461,108 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
|
||||||
dedicatedBufferUsage,
|
dedicatedBufferUsage,
|
||||||
dedicatedImage,
|
dedicatedImage,
|
||||||
allocationCount,
|
allocationCount,
|
||||||
|
pAllocations,
|
||||||
|
blockVector.GetAllocationNextPtr());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const bool canAllocateDedicated =
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
|
||||||
|
(pool == VK_NULL_HANDLE || !blockVector.HasExplicitBlockSize());
|
||||||
|
|
||||||
|
if(canAllocateDedicated)
|
||||||
|
{
|
||||||
|
// Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
|
||||||
|
if(size > blockVector.GetPreferredBlockSize() / 2)
|
||||||
|
{
|
||||||
|
dedicatedPreferred = true;
|
||||||
|
}
|
||||||
|
// Protection against creating each allocation as dedicated when we reach or exceed heap size/budget,
|
||||||
|
// which can quickly deplete maxMemoryAllocationCount: Don't prefer dedicated allocations when above
|
||||||
|
// 3/4 of the maximum allocation count.
|
||||||
|
if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4)
|
||||||
|
{
|
||||||
|
dedicatedPreferred = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dedicatedPreferred)
|
||||||
|
{
|
||||||
|
res = AllocateDedicatedMemory(
|
||||||
|
pool,
|
||||||
|
size,
|
||||||
|
suballocType,
|
||||||
|
dedicatedAllocations,
|
||||||
|
memTypeIndex,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0,
|
||||||
|
finalCreateInfo.pUserData,
|
||||||
|
finalCreateInfo.priority,
|
||||||
|
dedicatedBuffer,
|
||||||
|
dedicatedBufferUsage,
|
||||||
|
dedicatedImage,
|
||||||
|
allocationCount,
|
||||||
|
pAllocations,
|
||||||
|
blockVector.GetAllocationNextPtr());
|
||||||
|
if(res == VK_SUCCESS)
|
||||||
|
{
|
||||||
|
// Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
|
||||||
|
VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = blockVector.Allocate(
|
||||||
|
m_CurrentFrameIndex.load(),
|
||||||
|
size,
|
||||||
|
alignment,
|
||||||
|
finalCreateInfo,
|
||||||
|
suballocType,
|
||||||
|
allocationCount,
|
||||||
pAllocations);
|
pAllocations);
|
||||||
if(res == VK_SUCCESS)
|
if(res == VK_SUCCESS)
|
||||||
{
|
|
||||||
// Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
|
|
||||||
VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
|
|
||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
|
||||||
else
|
// Try dedicated memory.
|
||||||
|
if(canAllocateDedicated && !dedicatedPreferred)
|
||||||
{
|
{
|
||||||
// Everything failed: Return error code.
|
res = AllocateDedicatedMemory(
|
||||||
VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
|
pool,
|
||||||
return res;
|
size,
|
||||||
|
suballocType,
|
||||||
|
dedicatedAllocations,
|
||||||
|
memTypeIndex,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
|
||||||
|
(finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0,
|
||||||
|
finalCreateInfo.pUserData,
|
||||||
|
finalCreateInfo.priority,
|
||||||
|
dedicatedBuffer,
|
||||||
|
dedicatedBufferUsage,
|
||||||
|
dedicatedImage,
|
||||||
|
allocationCount,
|
||||||
|
pAllocations,
|
||||||
|
blockVector.GetAllocationNextPtr());
|
||||||
|
if(res == VK_SUCCESS)
|
||||||
|
{
|
||||||
|
// Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
|
||||||
|
VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Everything failed: Return error code.
|
||||||
|
VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::AllocateDedicatedMemory(
|
VkResult VmaAllocator_T::AllocateDedicatedMemory(
|
||||||
|
VmaPool pool,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VmaSuballocationType suballocType,
|
VmaSuballocationType suballocType,
|
||||||
|
VmaDedicatedAllocationList& dedicatedAllocations,
|
||||||
uint32_t memTypeIndex,
|
uint32_t memTypeIndex,
|
||||||
bool withinBudget,
|
|
||||||
bool map,
|
bool map,
|
||||||
bool isUserDataString,
|
bool isUserDataString,
|
||||||
bool canAliasMemory,
|
bool canAliasMemory,
|
||||||
|
@ -15497,24 +15572,15 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
|
||||||
VkBufferUsageFlags dedicatedBufferUsage,
|
VkBufferUsageFlags dedicatedBufferUsage,
|
||||||
VkImage dedicatedImage,
|
VkImage dedicatedImage,
|
||||||
size_t allocationCount,
|
size_t allocationCount,
|
||||||
VmaAllocation* pAllocations)
|
VmaAllocation* pAllocations,
|
||||||
|
const void* pNextChain)
|
||||||
{
|
{
|
||||||
VMA_ASSERT(allocationCount > 0 && pAllocations);
|
VMA_ASSERT(allocationCount > 0 && pAllocations);
|
||||||
|
|
||||||
if(withinBudget)
|
|
||||||
{
|
|
||||||
const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
|
|
||||||
VmaBudget heapBudget = {};
|
|
||||||
GetHeapBudgets(&heapBudget, heapIndex, 1);
|
|
||||||
if(heapBudget.usage + size * allocationCount > heapBudget.budget)
|
|
||||||
{
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||||
allocInfo.memoryTypeIndex = memTypeIndex;
|
allocInfo.memoryTypeIndex = memTypeIndex;
|
||||||
allocInfo.allocationSize = size;
|
allocInfo.allocationSize = size;
|
||||||
|
allocInfo.pNext = pNextChain;
|
||||||
|
|
||||||
#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
|
#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
|
||||||
VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
|
VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
|
||||||
|
@ -15583,6 +15649,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
|
||||||
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
|
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
|
||||||
{
|
{
|
||||||
res = AllocateDedicatedMemoryPage(
|
res = AllocateDedicatedMemoryPage(
|
||||||
|
pool,
|
||||||
size,
|
size,
|
||||||
suballocType,
|
suballocType,
|
||||||
memTypeIndex,
|
memTypeIndex,
|
||||||
|
@ -15599,15 +15666,10 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
|
||||||
|
|
||||||
if(res == VK_SUCCESS)
|
if(res == VK_SUCCESS)
|
||||||
{
|
{
|
||||||
// Register them in m_DedicatedAllocations.
|
for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
|
||||||
{
|
{
|
||||||
VmaDedicatedAllocationList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
|
dedicatedAllocations.Register(pAllocations[allocIndex]);
|
||||||
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
|
|
||||||
{
|
|
||||||
dedicatedAllocations.Register(pAllocations[allocIndex]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
|
VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -15641,6 +15703,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
|
VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
|
||||||
|
VmaPool pool,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VmaSuballocationType suballocType,
|
VmaSuballocationType suballocType,
|
||||||
uint32_t memTypeIndex,
|
uint32_t memTypeIndex,
|
||||||
|
@ -15677,7 +15740,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
|
||||||
}
|
}
|
||||||
|
|
||||||
*pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString);
|
*pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString);
|
||||||
(*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
|
(*pAllocation)->InitDedicatedAllocation(pool, memTypeIndex, hMemory, suballocType, pMappedData, size);
|
||||||
(*pAllocation)->SetUserData(this, pUserData);
|
(*pAllocation)->SetUserData(this, pUserData);
|
||||||
m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
|
m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
|
||||||
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
|
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
|
||||||
|
@ -15752,6 +15815,77 @@ void VmaAllocator_T::GetImageMemoryRequirements(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkResult VmaAllocator_T::CalcMemTypeParams(
|
||||||
|
VmaAllocationCreateInfo& inoutCreateInfo,
|
||||||
|
uint32_t memTypeIndex,
|
||||||
|
VkDeviceSize size,
|
||||||
|
size_t allocationCount)
|
||||||
|
{
|
||||||
|
// If memory type is not HOST_VISIBLE, disable MAPPED.
|
||||||
|
if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
|
||||||
|
(m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
|
||||||
|
{
|
||||||
|
inoutCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
|
||||||
|
(inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0)
|
||||||
|
{
|
||||||
|
const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
|
||||||
|
VmaBudget heapBudget = {};
|
||||||
|
GetHeapBudgets(&heapBudget, heapIndex, 1);
|
||||||
|
if(heapBudget.usage + size * allocationCount > heapBudget.budget)
|
||||||
|
{
|
||||||
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult VmaAllocator_T::CalcAllocationParams(
|
||||||
|
VmaAllocationCreateInfo& inoutCreateInfo,
|
||||||
|
bool dedicatedRequired,
|
||||||
|
bool dedicatedPreferred)
|
||||||
|
{
|
||||||
|
if(dedicatedRequired ||
|
||||||
|
// If memory is lazily allocated, it should be always dedicated.
|
||||||
|
inoutCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED)
|
||||||
|
{
|
||||||
|
inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inoutCreateInfo.pool != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
if(inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() &&
|
||||||
|
(inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
|
||||||
|
{
|
||||||
|
VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT while current custom pool doesn't support dedicated allocations.");
|
||||||
|
return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
inoutCreateInfo.priority = inoutCreateInfo.pool->m_BlockVector.GetPriority();
|
||||||
|
}
|
||||||
|
|
||||||
|
if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
|
||||||
|
(inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
|
||||||
|
{
|
||||||
|
VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
|
||||||
|
return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
|
||||||
|
(inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0)
|
||||||
|
{
|
||||||
|
VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
|
||||||
|
return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY &&
|
||||||
|
(inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
|
||||||
|
{
|
||||||
|
inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||||
|
}
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::AllocateMemory(
|
VkResult VmaAllocator_T::AllocateMemory(
|
||||||
const VkMemoryRequirements& vkMemReq,
|
const VkMemoryRequirements& vkMemReq,
|
||||||
bool requiresDedicatedAllocation,
|
bool requiresDedicatedAllocation,
|
||||||
|
@ -15772,54 +15906,28 @@ VkResult VmaAllocator_T::AllocateMemory(
|
||||||
{
|
{
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
|
|
||||||
(createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
|
|
||||||
{
|
|
||||||
VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
|
|
||||||
(createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0)
|
|
||||||
{
|
|
||||||
VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
if(requiresDedicatedAllocation)
|
|
||||||
{
|
|
||||||
if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
|
|
||||||
{
|
|
||||||
VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
if(createInfo.pool != VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
VMA_ASSERT(0 && "Pool specified while dedicated allocation is required.");
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((createInfo.pool != VK_NULL_HANDLE) &&
|
|
||||||
((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
|
|
||||||
{
|
|
||||||
VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(createInfo.pool != VK_NULL_HANDLE)
|
VmaAllocationCreateInfo createInfoFinal = createInfo;
|
||||||
{
|
VkResult res = CalcAllocationParams(createInfoFinal, requiresDedicatedAllocation, prefersDedicatedAllocation);
|
||||||
VmaAllocationCreateInfo createInfoForPool = createInfo;
|
if(res != VK_SUCCESS)
|
||||||
// If memory type is not HOST_VISIBLE, disable MAPPED.
|
return res;
|
||||||
if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
|
|
||||||
(m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
|
|
||||||
{
|
|
||||||
createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return createInfo.pool->m_BlockVector.Allocate(
|
if(createInfoFinal.pool != VK_NULL_HANDLE)
|
||||||
m_CurrentFrameIndex.load(),
|
{
|
||||||
|
VmaBlockVector& blockVector = createInfoFinal.pool->m_BlockVector;
|
||||||
|
return AllocateMemoryOfType(
|
||||||
|
createInfoFinal.pool,
|
||||||
vkMemReq.size,
|
vkMemReq.size,
|
||||||
vkMemReq.alignment,
|
vkMemReq.alignment,
|
||||||
createInfoForPool,
|
prefersDedicatedAllocation,
|
||||||
|
dedicatedBuffer,
|
||||||
|
dedicatedBufferUsage,
|
||||||
|
dedicatedImage,
|
||||||
|
createInfoFinal,
|
||||||
|
blockVector.GetMemoryTypeIndex(),
|
||||||
suballocType,
|
suballocType,
|
||||||
|
createInfoFinal.pool->m_DedicatedAllocations,
|
||||||
|
blockVector,
|
||||||
allocationCount,
|
allocationCount,
|
||||||
pAllocations);
|
pAllocations);
|
||||||
}
|
}
|
||||||
|
@ -15828,68 +15936,42 @@ VkResult VmaAllocator_T::AllocateMemory(
|
||||||
// Bit mask of memory Vulkan types acceptable for this allocation.
|
// Bit mask of memory Vulkan types acceptable for this allocation.
|
||||||
uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
|
uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
|
||||||
uint32_t memTypeIndex = UINT32_MAX;
|
uint32_t memTypeIndex = UINT32_MAX;
|
||||||
VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
|
res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfoFinal, &memTypeIndex);
|
||||||
if(res == VK_SUCCESS)
|
// Can't find any single memory type matching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
|
||||||
|
if(res != VK_SUCCESS)
|
||||||
|
return res;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
|
VmaBlockVector* blockVector = m_pBlockVectors[memTypeIndex];
|
||||||
|
VMA_ASSERT(blockVector && "Trying to use unsupported memory type!");
|
||||||
res = AllocateMemoryOfType(
|
res = AllocateMemoryOfType(
|
||||||
|
VK_NULL_HANDLE,
|
||||||
vkMemReq.size,
|
vkMemReq.size,
|
||||||
vkMemReq.alignment,
|
vkMemReq.alignment,
|
||||||
requiresDedicatedAllocation || prefersDedicatedAllocation,
|
requiresDedicatedAllocation || prefersDedicatedAllocation,
|
||||||
dedicatedBuffer,
|
dedicatedBuffer,
|
||||||
dedicatedBufferUsage,
|
dedicatedBufferUsage,
|
||||||
dedicatedImage,
|
dedicatedImage,
|
||||||
createInfo,
|
createInfoFinal,
|
||||||
memTypeIndex,
|
memTypeIndex,
|
||||||
suballocType,
|
suballocType,
|
||||||
|
m_DedicatedAllocations[memTypeIndex],
|
||||||
|
*blockVector,
|
||||||
allocationCount,
|
allocationCount,
|
||||||
pAllocations);
|
pAllocations);
|
||||||
// Succeeded on first try.
|
// Allocation succeeded
|
||||||
if(res == VK_SUCCESS)
|
if(res == VK_SUCCESS)
|
||||||
{
|
return VK_SUCCESS;
|
||||||
return res;
|
|
||||||
}
|
// Remove old memTypeIndex from list of possibilities.
|
||||||
// Allocation from this memory type failed. Try other compatible memory types.
|
memoryTypeBits &= ~(1u << memTypeIndex);
|
||||||
else
|
// Find alternative memTypeIndex.
|
||||||
{
|
res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfoFinal, &memTypeIndex);
|
||||||
for(;;)
|
} while(res == VK_SUCCESS);
|
||||||
{
|
|
||||||
// Remove old memTypeIndex from list of possibilities.
|
// No other matching memory type index could be found.
|
||||||
memoryTypeBits &= ~(1u << memTypeIndex);
|
// Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
|
||||||
// Find alternative memTypeIndex.
|
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||||
res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
|
|
||||||
if(res == VK_SUCCESS)
|
|
||||||
{
|
|
||||||
res = AllocateMemoryOfType(
|
|
||||||
vkMemReq.size,
|
|
||||||
vkMemReq.alignment,
|
|
||||||
requiresDedicatedAllocation || prefersDedicatedAllocation,
|
|
||||||
dedicatedBuffer,
|
|
||||||
dedicatedBufferUsage,
|
|
||||||
dedicatedImage,
|
|
||||||
createInfo,
|
|
||||||
memTypeIndex,
|
|
||||||
suballocType,
|
|
||||||
allocationCount,
|
|
||||||
pAllocations);
|
|
||||||
// Allocation from this alternative memory type succeeded.
|
|
||||||
if(res == VK_SUCCESS)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
// else: Allocation from this memory type failed. Try next one - next loop iteration.
|
|
||||||
}
|
|
||||||
// No other matching memory type index could be found.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
|
|
||||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
|
|
||||||
else
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15917,7 +15999,7 @@ void VmaAllocator_T::FreeMemory(
|
||||||
case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
|
case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
|
||||||
{
|
{
|
||||||
VmaBlockVector* pBlockVector = VMA_NULL;
|
VmaBlockVector* pBlockVector = VMA_NULL;
|
||||||
VmaPool hPool = allocation->GetBlock()->GetParentPool();
|
VmaPool hPool = allocation->GetParentPool();
|
||||||
if(hPool != VK_NULL_HANDLE)
|
if(hPool != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
pBlockVector = &hPool->m_BlockVector;
|
pBlockVector = &hPool->m_BlockVector;
|
||||||
|
@ -15969,7 +16051,11 @@ void VmaAllocator_T::CalculateStats(VmaStats* pStats)
|
||||||
VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
|
VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
|
||||||
for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
|
for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
|
||||||
{
|
{
|
||||||
pool->m_BlockVector.AddStats(pStats);
|
VmaBlockVector& blockVector = pool->m_BlockVector;
|
||||||
|
blockVector.AddStats(pStats);
|
||||||
|
const uint32_t memTypeIndex = blockVector.GetMemoryTypeIndex();
|
||||||
|
const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
|
||||||
|
pool->m_DedicatedAllocations.AddStats(pStats, memTypeIndex, memHeapIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15977,8 +16063,7 @@ void VmaAllocator_T::CalculateStats(VmaStats* pStats)
|
||||||
for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
|
for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
|
||||||
{
|
{
|
||||||
const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
|
const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
|
||||||
VmaDedicatedAllocationList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
|
m_DedicatedAllocations[memTypeIndex].AddStats(pStats, memTypeIndex, memHeapIndex);
|
||||||
m_DedicatedAllocations->CalculateStats(pStats, memTypeIndex, memHeapIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Postprocess.
|
// Postprocess.
|
||||||
|
@ -16041,8 +16126,6 @@ void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t VMA_VENDOR_ID_AMD = 4098;
|
|
||||||
|
|
||||||
VkResult VmaAllocator_T::DefragmentationBegin(
|
VkResult VmaAllocator_T::DefragmentationBegin(
|
||||||
const VmaDefragmentationInfo2& info,
|
const VmaDefragmentationInfo2& info,
|
||||||
VmaDefragmentationStats* pStats,
|
VmaDefragmentationStats* pStats,
|
||||||
|
@ -16087,11 +16170,11 @@ VkResult VmaAllocator_T::DefragmentationPassBegin(
|
||||||
{
|
{
|
||||||
return context->DefragmentPassBegin(pInfo);
|
return context->DefragmentPassBegin(pInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::DefragmentationPassEnd(
|
VkResult VmaAllocator_T::DefragmentationPassEnd(
|
||||||
VmaDefragmentationContext context)
|
VmaDefragmentationContext context)
|
||||||
{
|
{
|
||||||
return context->DefragmentPassEnd();
|
return context->DefragmentPassEnd();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
|
void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
|
||||||
|
@ -16368,31 +16451,6 @@ 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 T>
|
|
||||||
struct AtomicTransactionalIncrement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::atomic<T> AtomicT;
|
|
||||||
~AtomicTransactionalIncrement()
|
|
||||||
{
|
|
||||||
if(m_Atomic)
|
|
||||||
--(*m_Atomic);
|
|
||||||
}
|
|
||||||
T 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<uint32_t> deviceMemoryCountIncrement;
|
AtomicTransactionalIncrement<uint32_t> deviceMemoryCountIncrement;
|
||||||
|
@ -16702,9 +16760,16 @@ void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
|
||||||
VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
|
VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
|
||||||
|
|
||||||
const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
|
const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
|
||||||
|
VmaPool parentPool = allocation->GetParentPool();
|
||||||
|
if(parentPool == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
VmaDedicatedAllocationList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
|
// Default pool
|
||||||
dedicatedAllocations.Unregister(allocation);
|
m_DedicatedAllocations[memTypeIndex].Unregister(allocation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Custom pool
|
||||||
|
parentPool->m_DedicatedAllocations.Unregister(allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDeviceMemory hMemory = allocation->GetMemory();
|
VkDeviceMemory hMemory = allocation->GetMemory();
|
||||||
|
@ -16954,7 +17019,9 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
|
||||||
json.ContinueString(memTypeIndex);
|
json.ContinueString(memTypeIndex);
|
||||||
json.EndString();
|
json.EndString();
|
||||||
|
|
||||||
|
json.BeginObject();
|
||||||
pBlockVector->PrintDetailedMap(json);
|
pBlockVector->PrintDetailedMap(json);
|
||||||
|
json.EndObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16977,7 +17044,17 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
|
||||||
json.ContinueString(pool->GetId());
|
json.ContinueString(pool->GetId());
|
||||||
json.EndString();
|
json.EndString();
|
||||||
|
|
||||||
|
json.BeginObject();
|
||||||
pool->m_BlockVector.PrintDetailedMap(json);
|
pool->m_BlockVector.PrintDetailedMap(json);
|
||||||
|
|
||||||
|
if (!pool->m_DedicatedAllocations.IsEmpty())
|
||||||
|
{
|
||||||
|
json.WriteString("DedicatedAllocations");
|
||||||
|
json.BeginObject();
|
||||||
|
pool->m_DedicatedAllocations.BuildStatsString(json);
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
}
|
}
|
||||||
json.EndObject();
|
json.EndObject();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,305 +1,317 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2018-2021 Advanced Micro Devices, Inc. All rights reserved.
|
# Copyright (c) 2018-2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
# in the Software without restriction, including without limitation the rights
|
# in the Software without restriction, including without limitation the rights
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
# furnished to do so, subject to the following conditions:
|
# furnished to do so, subject to the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in
|
# The above copyright notice and this permission notice shall be included in
|
||||||
# all copies or substantial portions of the Software.
|
# all copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
|
||||||
PROGRAM_VERSION = 'VMA Dump Visualization 2.0.1'
|
PROGRAM_VERSION = 'VMA Dump Visualization 2.0.1'
|
||||||
IMG_SIZE_X = 1200
|
IMG_SIZE_X = 1200
|
||||||
IMG_MARGIN = 8
|
IMG_MARGIN = 8
|
||||||
FONT_SIZE = 10
|
FONT_SIZE = 10
|
||||||
MAP_SIZE = 24
|
MAP_SIZE = 24
|
||||||
COLOR_TEXT_H1 = (0, 0, 0, 255)
|
COLOR_TEXT_H1 = (0, 0, 0, 255)
|
||||||
COLOR_TEXT_H2 = (150, 150, 150, 255)
|
COLOR_TEXT_H2 = (150, 150, 150, 255)
|
||||||
COLOR_OUTLINE = (155, 155, 155, 255)
|
COLOR_OUTLINE = (155, 155, 155, 255)
|
||||||
COLOR_OUTLINE_HARD = (0, 0, 0, 255)
|
COLOR_OUTLINE_HARD = (0, 0, 0, 255)
|
||||||
COLOR_GRID_LINE = (224, 224, 224, 255)
|
COLOR_GRID_LINE = (224, 224, 224, 255)
|
||||||
|
|
||||||
|
|
||||||
argParser = argparse.ArgumentParser(description='Visualization of Vulkan Memory Allocator JSON dump.')
|
argParser = argparse.ArgumentParser(description='Visualization of Vulkan Memory Allocator JSON dump.')
|
||||||
argParser.add_argument('DumpFile', type=argparse.FileType(mode='r', encoding='UTF-8'), help='Path to source JSON file with memory dump created by Vulkan Memory Allocator library')
|
argParser.add_argument('DumpFile', type=argparse.FileType(mode='r', encoding='UTF-8'), help='Path to source JSON file with memory dump created by Vulkan Memory Allocator library')
|
||||||
argParser.add_argument('-v', '--version', action='version', version=PROGRAM_VERSION)
|
argParser.add_argument('-v', '--version', action='version', version=PROGRAM_VERSION)
|
||||||
argParser.add_argument('-o', '--output', required=True, help='Path to destination image file (e.g. PNG)')
|
argParser.add_argument('-o', '--output', required=True, help='Path to destination image file (e.g. PNG)')
|
||||||
args = argParser.parse_args()
|
args = argParser.parse_args()
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
|
||||||
def ProcessBlock(dstBlockList, iBlockId, objBlock, sAlgorithm):
|
def ProcessBlock(dstBlockList, iBlockId, objBlock, sAlgorithm):
|
||||||
iBlockSize = int(objBlock['TotalBytes'])
|
iBlockSize = int(objBlock['TotalBytes'])
|
||||||
arrSuballocs = objBlock['Suballocations']
|
arrSuballocs = objBlock['Suballocations']
|
||||||
dstBlockObj = {'ID': iBlockId, 'Size':iBlockSize, 'Suballocations':[]}
|
dstBlockObj = {'ID': iBlockId, 'Size':iBlockSize, 'Suballocations':[]}
|
||||||
dstBlockObj['Algorithm'] = sAlgorithm
|
dstBlockObj['Algorithm'] = sAlgorithm
|
||||||
for objSuballoc in arrSuballocs:
|
for objSuballoc in arrSuballocs:
|
||||||
dstBlockObj['Suballocations'].append((objSuballoc['Type'], int(objSuballoc['Size']), int(objSuballoc['Usage']) if ('Usage' in objSuballoc) else 0))
|
dstBlockObj['Suballocations'].append((objSuballoc['Type'], int(objSuballoc['Size']), int(objSuballoc['Usage']) if ('Usage' in objSuballoc) else 0))
|
||||||
dstBlockList.append(dstBlockObj)
|
dstBlockList.append(dstBlockObj)
|
||||||
|
|
||||||
|
|
||||||
def GetDataForMemoryType(iMemTypeIndex):
|
def GetDataForMemoryType(iMemTypeIndex):
|
||||||
global data
|
global data
|
||||||
if iMemTypeIndex in data:
|
if iMemTypeIndex in data:
|
||||||
return data[iMemTypeIndex]
|
return data[iMemTypeIndex]
|
||||||
else:
|
else:
|
||||||
newMemTypeData = {'DedicatedAllocations':[], 'DefaultPoolBlocks':[], 'CustomPools':{}}
|
newMemTypeData = {'DedicatedAllocations':[], 'DefaultPoolBlocks':[], 'CustomPools':{}}
|
||||||
data[iMemTypeIndex] = newMemTypeData
|
data[iMemTypeIndex] = newMemTypeData
|
||||||
return newMemTypeData
|
return newMemTypeData
|
||||||
|
|
||||||
|
|
||||||
def IsDataEmpty():
|
def IsDataEmpty():
|
||||||
global data
|
global data
|
||||||
for dictMemType in data.values():
|
for dictMemType in data.values():
|
||||||
if 'DedicatedAllocations' in dictMemType and len(dictMemType['DedicatedAllocations']) > 0:
|
if 'DedicatedAllocations' in dictMemType and len(dictMemType['DedicatedAllocations']) > 0:
|
||||||
return False
|
return False
|
||||||
if 'DefaultPoolBlocks' in dictMemType and len(dictMemType['DefaultPoolBlocks']) > 0:
|
if 'DefaultPoolBlocks' in dictMemType and len(dictMemType['DefaultPoolBlocks']) > 0:
|
||||||
return False
|
return False
|
||||||
if 'CustomPools' in dictMemType:
|
if 'CustomPools' in dictMemType:
|
||||||
for lBlockList in dictMemType['CustomPools'].values():
|
for lBlockList in dictMemType['CustomPools'].values():
|
||||||
if len(lBlockList) > 0:
|
if len(lBlockList) > 0:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# Returns tuple:
|
# Returns tuple:
|
||||||
# [0] image height : integer
|
# [0] image height : integer
|
||||||
# [1] pixels per byte : float
|
# [1] pixels per byte : float
|
||||||
def CalcParams():
|
def CalcParams():
|
||||||
global data
|
global data
|
||||||
iImgSizeY = IMG_MARGIN
|
iImgSizeY = IMG_MARGIN
|
||||||
iImgSizeY += FONT_SIZE + IMG_MARGIN # Grid lines legend - sizes
|
iImgSizeY += FONT_SIZE + IMG_MARGIN # Grid lines legend - sizes
|
||||||
iMaxBlockSize = 0
|
iMaxBlockSize = 0
|
||||||
for dictMemType in data.values():
|
for dictMemType in data.values():
|
||||||
iImgSizeY += IMG_MARGIN + FONT_SIZE
|
iImgSizeY += IMG_MARGIN + FONT_SIZE
|
||||||
lDedicatedAllocations = dictMemType['DedicatedAllocations']
|
lDedicatedAllocations = dictMemType['DedicatedAllocations']
|
||||||
iImgSizeY += len(lDedicatedAllocations) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
iImgSizeY += len(lDedicatedAllocations) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
for tDedicatedAlloc in lDedicatedAllocations:
|
for tDedicatedAlloc in lDedicatedAllocations:
|
||||||
iMaxBlockSize = max(iMaxBlockSize, tDedicatedAlloc[1])
|
iMaxBlockSize = max(iMaxBlockSize, tDedicatedAlloc[1])
|
||||||
lDefaultPoolBlocks = dictMemType['DefaultPoolBlocks']
|
lDefaultPoolBlocks = dictMemType['DefaultPoolBlocks']
|
||||||
iImgSizeY += len(lDefaultPoolBlocks) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
iImgSizeY += len(lDefaultPoolBlocks) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
for objBlock in lDefaultPoolBlocks:
|
for objBlock in lDefaultPoolBlocks:
|
||||||
iMaxBlockSize = max(iMaxBlockSize, objBlock['Size'])
|
iMaxBlockSize = max(iMaxBlockSize, objBlock['Size'])
|
||||||
dCustomPools = dictMemType['CustomPools']
|
dCustomPools = dictMemType['CustomPools']
|
||||||
for lBlocks in dCustomPools.values():
|
for lBlocks in dCustomPools.values():
|
||||||
iImgSizeY += len(lBlocks) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
iImgSizeY += len(lBlocks) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
for objBlock in lBlocks:
|
for objBlock in lBlocks:
|
||||||
iMaxBlockSize = max(iMaxBlockSize, objBlock['Size'])
|
iMaxBlockSize = max(iMaxBlockSize, objBlock['Size'])
|
||||||
fPixelsPerByte = (IMG_SIZE_X - IMG_MARGIN * 2) / float(iMaxBlockSize)
|
fPixelsPerByte = (IMG_SIZE_X - IMG_MARGIN * 2) / float(iMaxBlockSize)
|
||||||
return iImgSizeY, fPixelsPerByte
|
return iImgSizeY, fPixelsPerByte
|
||||||
|
|
||||||
|
|
||||||
def TypeToColor(sType, iUsage):
|
def TypeToColor(sType, iUsage):
|
||||||
if sType == 'FREE':
|
if sType == 'FREE':
|
||||||
return 220, 220, 220, 255
|
return 220, 220, 220, 255
|
||||||
elif sType == 'BUFFER':
|
elif sType == 'BUFFER':
|
||||||
if (iUsage & 0x1C0) != 0: # INDIRECT_BUFFER | VERTEX_BUFFER | INDEX_BUFFER
|
if (iUsage & 0x1C0) != 0: # INDIRECT_BUFFER | VERTEX_BUFFER | INDEX_BUFFER
|
||||||
return 255, 148, 148, 255 # Red
|
return 255, 148, 148, 255 # Red
|
||||||
elif (iUsage & 0x28) != 0: # STORAGE_BUFFER | STORAGE_TEXEL_BUFFER
|
elif (iUsage & 0x28) != 0: # STORAGE_BUFFER | STORAGE_TEXEL_BUFFER
|
||||||
return 255, 187, 121, 255 # Orange
|
return 255, 187, 121, 255 # Orange
|
||||||
elif (iUsage & 0x14) != 0: # UNIFORM_BUFFER | UNIFORM_TEXEL_BUFFER
|
elif (iUsage & 0x14) != 0: # UNIFORM_BUFFER | UNIFORM_TEXEL_BUFFER
|
||||||
return 255, 255, 0, 255 # Yellow
|
return 255, 255, 0, 255 # Yellow
|
||||||
else:
|
else:
|
||||||
return 255, 255, 165, 255 # Light yellow
|
return 255, 255, 165, 255 # Light yellow
|
||||||
elif sType == 'IMAGE_OPTIMAL':
|
elif sType == 'IMAGE_OPTIMAL':
|
||||||
if (iUsage & 0x20) != 0: # DEPTH_STENCIL_ATTACHMENT
|
if (iUsage & 0x20) != 0: # DEPTH_STENCIL_ATTACHMENT
|
||||||
return 246, 128, 255, 255 # Pink
|
return 246, 128, 255, 255 # Pink
|
||||||
elif (iUsage & 0xD0) != 0: # INPUT_ATTACHMENT | TRANSIENT_ATTACHMENT | COLOR_ATTACHMENT
|
elif (iUsage & 0xD0) != 0: # INPUT_ATTACHMENT | TRANSIENT_ATTACHMENT | COLOR_ATTACHMENT
|
||||||
return 179, 179, 255, 255 # Blue
|
return 179, 179, 255, 255 # Blue
|
||||||
elif (iUsage & 0x4) != 0: # SAMPLED
|
elif (iUsage & 0x4) != 0: # SAMPLED
|
||||||
return 0, 255, 255, 255 # Aqua
|
return 0, 255, 255, 255 # Aqua
|
||||||
else:
|
else:
|
||||||
return 183, 255, 255, 255 # Light aqua
|
return 183, 255, 255, 255 # Light aqua
|
||||||
elif sType == 'IMAGE_LINEAR':
|
elif sType == 'IMAGE_LINEAR':
|
||||||
return 0, 255, 0, 255 # Green
|
return 0, 255, 0, 255 # Green
|
||||||
elif sType == 'IMAGE_UNKNOWN':
|
elif sType == 'IMAGE_UNKNOWN':
|
||||||
return 0, 255, 164, 255 # Green/aqua
|
return 0, 255, 164, 255 # Green/aqua
|
||||||
elif sType == 'UNKNOWN':
|
elif sType == 'UNKNOWN':
|
||||||
return 175, 175, 175, 255 # Gray
|
return 175, 175, 175, 255 # Gray
|
||||||
assert False
|
assert False
|
||||||
return 0, 0, 0, 255
|
return 0, 0, 0, 255
|
||||||
|
|
||||||
|
|
||||||
def DrawDedicatedAllocationBlock(draw, y, tDedicatedAlloc):
|
def DrawDedicatedAllocationBlock(draw, y, tDedicatedAlloc):
|
||||||
global fPixelsPerByte
|
global fPixelsPerByte
|
||||||
iSizeBytes = tDedicatedAlloc[1]
|
iSizeBytes = tDedicatedAlloc[1]
|
||||||
iSizePixels = int(iSizeBytes * fPixelsPerByte)
|
iSizePixels = int(iSizeBytes * fPixelsPerByte)
|
||||||
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + iSizePixels, y + MAP_SIZE], fill=TypeToColor(tDedicatedAlloc[0], tDedicatedAlloc[2]), outline=COLOR_OUTLINE)
|
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + iSizePixels, y + MAP_SIZE], fill=TypeToColor(tDedicatedAlloc[0], tDedicatedAlloc[2]), outline=COLOR_OUTLINE)
|
||||||
|
|
||||||
|
|
||||||
def DrawBlock(draw, y, objBlock):
|
def DrawBlock(draw, y, objBlock):
|
||||||
global fPixelsPerByte
|
global fPixelsPerByte
|
||||||
iSizeBytes = objBlock['Size']
|
iSizeBytes = objBlock['Size']
|
||||||
iSizePixels = int(iSizeBytes * fPixelsPerByte)
|
iSizePixels = int(iSizeBytes * fPixelsPerByte)
|
||||||
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + iSizePixels, y + MAP_SIZE], fill=TypeToColor('FREE', 0), outline=None)
|
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + iSizePixels, y + MAP_SIZE], fill=TypeToColor('FREE', 0), outline=None)
|
||||||
iByte = 0
|
iByte = 0
|
||||||
iX = 0
|
iX = 0
|
||||||
iLastHardLineX = -1
|
iLastHardLineX = -1
|
||||||
for tSuballoc in objBlock['Suballocations']:
|
for tSuballoc in objBlock['Suballocations']:
|
||||||
sType = tSuballoc[0]
|
sType = tSuballoc[0]
|
||||||
iByteEnd = iByte + tSuballoc[1]
|
iByteEnd = iByte + tSuballoc[1]
|
||||||
iXEnd = int(iByteEnd * fPixelsPerByte)
|
iXEnd = int(iByteEnd * fPixelsPerByte)
|
||||||
if sType != 'FREE':
|
if sType != 'FREE':
|
||||||
if iXEnd > iX + 1:
|
if iXEnd > iX + 1:
|
||||||
iUsage = tSuballoc[2]
|
iUsage = tSuballoc[2]
|
||||||
draw.rectangle([IMG_MARGIN + iX, y, IMG_MARGIN + iXEnd, y + MAP_SIZE], fill=TypeToColor(sType, iUsage), outline=COLOR_OUTLINE)
|
draw.rectangle([IMG_MARGIN + iX, y, IMG_MARGIN + iXEnd, y + MAP_SIZE], fill=TypeToColor(sType, iUsage), outline=COLOR_OUTLINE)
|
||||||
# Hard line was been overwritten by rectangle outline: redraw it.
|
# Hard line was been overwritten by rectangle outline: redraw it.
|
||||||
if iLastHardLineX == iX:
|
if iLastHardLineX == iX:
|
||||||
draw.line([IMG_MARGIN + iX, y, IMG_MARGIN + iX, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
draw.line([IMG_MARGIN + iX, y, IMG_MARGIN + iX, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
||||||
else:
|
else:
|
||||||
draw.line([IMG_MARGIN + iX, y, IMG_MARGIN + iX, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
draw.line([IMG_MARGIN + iX, y, IMG_MARGIN + iX, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
||||||
iLastHardLineX = iX
|
iLastHardLineX = iX
|
||||||
iByte = iByteEnd
|
iByte = iByteEnd
|
||||||
iX = iXEnd
|
iX = iXEnd
|
||||||
|
|
||||||
|
|
||||||
def BytesToStr(iBytes):
|
def BytesToStr(iBytes):
|
||||||
if iBytes < 1024:
|
if iBytes < 1024:
|
||||||
return "%d B" % iBytes
|
return "%d B" % iBytes
|
||||||
iBytes /= 1024
|
iBytes /= 1024
|
||||||
if iBytes < 1024:
|
if iBytes < 1024:
|
||||||
return "%d KiB" % iBytes
|
return "%d KiB" % iBytes
|
||||||
iBytes /= 1024
|
iBytes /= 1024
|
||||||
if iBytes < 1024:
|
if iBytes < 1024:
|
||||||
return "%d MiB" % iBytes
|
return "%d MiB" % iBytes
|
||||||
iBytes /= 1024
|
iBytes /= 1024
|
||||||
return "%d GiB" % iBytes
|
return "%d GiB" % iBytes
|
||||||
|
|
||||||
|
|
||||||
jsonSrc = json.load(args.DumpFile)
|
jsonSrc = json.load(args.DumpFile)
|
||||||
if 'DedicatedAllocations' in jsonSrc:
|
if 'DedicatedAllocations' in jsonSrc:
|
||||||
for tType in jsonSrc['DedicatedAllocations'].items():
|
for tType in jsonSrc['DedicatedAllocations'].items():
|
||||||
sType = tType[0]
|
sType = tType[0]
|
||||||
assert sType[:5] == 'Type '
|
assert sType[:5] == 'Type '
|
||||||
iType = int(sType[5:])
|
iType = int(sType[5:])
|
||||||
typeData = GetDataForMemoryType(iType)
|
typeData = GetDataForMemoryType(iType)
|
||||||
for objAlloc in tType[1]:
|
for objAlloc in tType[1]:
|
||||||
typeData['DedicatedAllocations'].append((objAlloc['Type'], int(objAlloc['Size']), int(objAlloc['Usage']) if ('Usage' in objAlloc) else 0))
|
typeData['DedicatedAllocations'].append((objAlloc['Type'], int(objAlloc['Size']), int(objAlloc['Usage']) if ('Usage' in objAlloc) else 0))
|
||||||
if 'DefaultPools' in jsonSrc:
|
if 'DefaultPools' in jsonSrc:
|
||||||
for tType in jsonSrc['DefaultPools'].items():
|
for tType in jsonSrc['DefaultPools'].items():
|
||||||
sType = tType[0]
|
sType = tType[0]
|
||||||
assert sType[:5] == 'Type '
|
assert sType[:5] == 'Type '
|
||||||
iType = int(sType[5:])
|
iType = int(sType[5:])
|
||||||
typeData = GetDataForMemoryType(iType)
|
typeData = GetDataForMemoryType(iType)
|
||||||
for sBlockId, objBlock in tType[1]['Blocks'].items():
|
for sBlockId, objBlock in tType[1]['Blocks'].items():
|
||||||
ProcessBlock(typeData['DefaultPoolBlocks'], int(sBlockId), objBlock, '')
|
ProcessBlock(typeData['DefaultPoolBlocks'], int(sBlockId), objBlock, '')
|
||||||
if 'Pools' in jsonSrc:
|
if 'Pools' in jsonSrc:
|
||||||
objPools = jsonSrc['Pools']
|
objPools = jsonSrc['Pools']
|
||||||
for sPoolId, objPool in objPools.items():
|
for sPoolId, objPool in objPools.items():
|
||||||
iType = int(objPool['MemoryTypeIndex'])
|
iType = int(objPool['MemoryTypeIndex'])
|
||||||
typeData = GetDataForMemoryType(iType)
|
typeData = GetDataForMemoryType(iType)
|
||||||
objBlocks = objPool['Blocks']
|
objBlocks = objPool['Blocks']
|
||||||
sAlgorithm = objPool.get('Algorithm', '')
|
sAlgorithm = objPool.get('Algorithm', '')
|
||||||
sName = objPool.get('Name', None)
|
sName = objPool.get('Name', None)
|
||||||
if sName:
|
if sName:
|
||||||
sFullName = sPoolId + ' "' + sName + '"'
|
sFullName = sPoolId + ' "' + sName + '"'
|
||||||
else:
|
else:
|
||||||
sFullName = sPoolId
|
sFullName = sPoolId
|
||||||
dstBlockArray = []
|
dstBlockArray = []
|
||||||
typeData['CustomPools'][sFullName] = dstBlockArray
|
typeData['CustomPools'][sFullName] = dstBlockArray
|
||||||
for sBlockId, objBlock in objBlocks.items():
|
for sBlockId, objBlock in objBlocks.items():
|
||||||
ProcessBlock(dstBlockArray, int(sBlockId), objBlock, sAlgorithm)
|
ProcessBlock(dstBlockArray, int(sBlockId), objBlock, sAlgorithm)
|
||||||
|
if 'DedicatedAllocations' in objPool:
|
||||||
if IsDataEmpty():
|
for tType in objPool['DedicatedAllocations'].items():
|
||||||
print("There is nothing to put on the image. Please make sure you generated the stats string with detailed map enabled.")
|
sType = tType[0]
|
||||||
exit(1)
|
assert sType[:5] == 'Type '
|
||||||
|
iType = int(sType[5:])
|
||||||
iImgSizeY, fPixelsPerByte = CalcParams()
|
typeData = GetDataForMemoryType(iType)
|
||||||
|
for objAlloc in tType[1]:
|
||||||
img = Image.new('RGB', (IMG_SIZE_X, iImgSizeY), 'white')
|
typeData['CustomPools'][sFullName].append((objAlloc['Type'], int(objAlloc['Size']), int(objAlloc['Usage']) if ('Usage' in objAlloc) else 0))
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
try:
|
if IsDataEmpty():
|
||||||
font = ImageFont.truetype('segoeuib.ttf')
|
print("There is nothing to put on the image. Please make sure you generated the stats string with detailed map enabled.")
|
||||||
except:
|
exit(1)
|
||||||
font = ImageFont.load_default()
|
|
||||||
|
iImgSizeY, fPixelsPerByte = CalcParams()
|
||||||
y = IMG_MARGIN
|
|
||||||
|
img = Image.new('RGB', (IMG_SIZE_X, iImgSizeY), 'white')
|
||||||
# Draw grid lines
|
draw = ImageDraw.Draw(img)
|
||||||
iBytesBetweenGridLines = 32
|
|
||||||
while iBytesBetweenGridLines * fPixelsPerByte < 64:
|
try:
|
||||||
iBytesBetweenGridLines *= 2
|
font = ImageFont.truetype('segoeuib.ttf')
|
||||||
iByte = 0
|
except:
|
||||||
TEXT_MARGIN = 4
|
font = ImageFont.load_default()
|
||||||
while True:
|
|
||||||
iX = int(iByte * fPixelsPerByte)
|
y = IMG_MARGIN
|
||||||
if iX > IMG_SIZE_X - 2 * IMG_MARGIN:
|
|
||||||
break
|
# Draw grid lines
|
||||||
draw.line([iX + IMG_MARGIN, 0, iX + IMG_MARGIN, iImgSizeY], fill=COLOR_GRID_LINE)
|
iBytesBetweenGridLines = 32
|
||||||
if iByte == 0:
|
while iBytesBetweenGridLines * fPixelsPerByte < 64:
|
||||||
draw.text((iX + IMG_MARGIN + TEXT_MARGIN, y), "0", fill=COLOR_TEXT_H2, font=font)
|
iBytesBetweenGridLines *= 2
|
||||||
else:
|
iByte = 0
|
||||||
text = BytesToStr(iByte)
|
TEXT_MARGIN = 4
|
||||||
textSize = draw.textsize(text, font=font)
|
while True:
|
||||||
draw.text((iX + IMG_MARGIN - textSize[0] - TEXT_MARGIN, y), text, fill=COLOR_TEXT_H2, font=font)
|
iX = int(iByte * fPixelsPerByte)
|
||||||
iByte += iBytesBetweenGridLines
|
if iX > IMG_SIZE_X - 2 * IMG_MARGIN:
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
break
|
||||||
|
draw.line([iX + IMG_MARGIN, 0, iX + IMG_MARGIN, iImgSizeY], fill=COLOR_GRID_LINE)
|
||||||
# Draw main content
|
if iByte == 0:
|
||||||
for iMemTypeIndex in sorted(data.keys()):
|
draw.text((iX + IMG_MARGIN + TEXT_MARGIN, y), "0", fill=COLOR_TEXT_H2, font=font)
|
||||||
dictMemType = data[iMemTypeIndex]
|
else:
|
||||||
draw.text((IMG_MARGIN, y), "Memory type %d" % iMemTypeIndex, fill=COLOR_TEXT_H1, font=font)
|
text = BytesToStr(iByte)
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
textSize = draw.textsize(text, font=font)
|
||||||
index = 0
|
draw.text((iX + IMG_MARGIN - textSize[0] - TEXT_MARGIN, y), text, fill=COLOR_TEXT_H2, font=font)
|
||||||
for tDedicatedAlloc in dictMemType['DedicatedAllocations']:
|
iByte += iBytesBetweenGridLines
|
||||||
draw.text((IMG_MARGIN, y), "Dedicated allocation %d" % index, fill=COLOR_TEXT_H2, font=font)
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
DrawDedicatedAllocationBlock(draw, y, tDedicatedAlloc)
|
# Draw main content
|
||||||
y += MAP_SIZE + IMG_MARGIN
|
for iMemTypeIndex in sorted(data.keys()):
|
||||||
index += 1
|
dictMemType = data[iMemTypeIndex]
|
||||||
for objBlock in dictMemType['DefaultPoolBlocks']:
|
draw.text((IMG_MARGIN, y), "Memory type %d" % iMemTypeIndex, fill=COLOR_TEXT_H1, font=font)
|
||||||
draw.text((IMG_MARGIN, y), "Default pool block %d" % objBlock['ID'], fill=COLOR_TEXT_H2, font=font)
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
index = 0
|
||||||
DrawBlock(draw, y, objBlock)
|
for tDedicatedAlloc in dictMemType['DedicatedAllocations']:
|
||||||
y += MAP_SIZE + IMG_MARGIN
|
draw.text((IMG_MARGIN, y), "Dedicated allocation %d" % index, fill=COLOR_TEXT_H2, font=font)
|
||||||
index = 0
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
for sPoolName, listPool in dictMemType['CustomPools'].items():
|
DrawDedicatedAllocationBlock(draw, y, tDedicatedAlloc)
|
||||||
for objBlock in listPool:
|
y += MAP_SIZE + IMG_MARGIN
|
||||||
if 'Algorithm' in objBlock and objBlock['Algorithm']:
|
index += 1
|
||||||
sAlgorithm = ' (Algorithm: %s)' % (objBlock['Algorithm'])
|
for objBlock in dictMemType['DefaultPoolBlocks']:
|
||||||
else:
|
draw.text((IMG_MARGIN, y), "Default pool block %d" % objBlock['ID'], fill=COLOR_TEXT_H2, font=font)
|
||||||
sAlgorithm = ''
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
draw.text((IMG_MARGIN, y), "Custom pool %s%s block %d" % (sPoolName, sAlgorithm, objBlock['ID']), fill=COLOR_TEXT_H2, font=font)
|
DrawBlock(draw, y, objBlock)
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
y += MAP_SIZE + IMG_MARGIN
|
||||||
DrawBlock(draw, y, objBlock)
|
index = 0
|
||||||
y += MAP_SIZE + IMG_MARGIN
|
for sPoolName, listPool in dictMemType['CustomPools'].items():
|
||||||
index += 1
|
for objBlock in listPool:
|
||||||
del draw
|
if 'Algorithm' in objBlock and objBlock['Algorithm']:
|
||||||
img.save(args.output)
|
sAlgorithm = ' (Algorithm: %s)' % (objBlock['Algorithm'])
|
||||||
|
else:
|
||||||
"""
|
sAlgorithm = ''
|
||||||
Main data structure - variable `data` - is a dictionary. Key is integer - memory type index. Value is dictionary of:
|
draw.text((IMG_MARGIN, y), "Custom pool %s%s block %d" % (sPoolName, sAlgorithm, objBlock['ID']), fill=COLOR_TEXT_H2, font=font)
|
||||||
- Fixed key 'DedicatedAllocations'. Value is list of tuples, each containing:
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
- [0]: Type : string
|
DrawBlock(draw, y, objBlock)
|
||||||
- [1]: Size : integer
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
- [2]: Usage : integer (0 if unknown)
|
DrawDedicatedAllocationBlock(draw, y, objBlock['DedicatedAllocations'])
|
||||||
- Fixed key 'DefaultPoolBlocks'. Value is list of objects, each containing dictionary with:
|
y += MAP_SIZE + IMG_MARGIN
|
||||||
- Fixed key 'ID'. Value is int.
|
index += 1
|
||||||
- Fixed key 'Size'. Value is int.
|
del draw
|
||||||
- Fixed key 'Suballocations'. Value is list of tuples as above.
|
img.save(args.output)
|
||||||
- Fixed key 'CustomPools'. Value is dictionary.
|
|
||||||
- Key is string with pool ID/name. Value is list of objects representing memory blocks, each containing dictionary with:
|
"""
|
||||||
- Fixed key 'ID'. Value is int.
|
Main data structure - variable `data` - is a dictionary. Key is integer - memory type index. Value is dictionary of:
|
||||||
- Fixed key 'Size'. Value is int.
|
- Fixed key 'DedicatedAllocations'. Value is list of tuples, each containing:
|
||||||
- Fixed key 'Algorithm'. Optional. Value is string.
|
- [0]: Type : string
|
||||||
- Fixed key 'Suballocations'. Value is list of tuples as above.
|
- [1]: Size : integer
|
||||||
"""
|
- [2]: Usage : integer (0 if unknown)
|
||||||
|
- Fixed key 'DefaultPoolBlocks'. Value is list of objects, each containing dictionary with:
|
||||||
|
- Fixed key 'ID'. Value is int.
|
||||||
|
- Fixed key 'Size'. Value is int.
|
||||||
|
- Fixed key 'Suballocations'. Value is list of tuples as above.
|
||||||
|
- Fixed key 'CustomPools'. Value is dictionary.
|
||||||
|
- Key is string with pool ID/name. Value is list of objects representing memory blocks, each containing dictionary with:
|
||||||
|
- Fixed key 'ID'. Value is int.
|
||||||
|
- Fixed key 'Size'. Value is int.
|
||||||
|
- Fixed key 'Algorithm'. Optional. Value is string.
|
||||||
|
- Fixed key 'Suballocations'. Value is list of tuples as above.
|
||||||
|
- Fixed key 'DedicatedAllocations'. Value is list of tuples as above.
|
||||||
|
"""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue