mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2024-11-27 00:44:35 +00:00
More refactoring in preparation for GPU memory defragmentation. Created classes: VmaBlockDefragmentationContext, VmaBlockVectorDefragmentationContext. Class VmaDefragmentationContext_T is no longer empty.
This commit is contained in:
parent
a9f030d7ba
commit
2dcfcf8b63
@ -1580,6 +1580,7 @@ typedef struct VmaVulkanFunctions {
|
|||||||
PFN_vkDestroyBuffer vkDestroyBuffer;
|
PFN_vkDestroyBuffer vkDestroyBuffer;
|
||||||
PFN_vkCreateImage vkCreateImage;
|
PFN_vkCreateImage vkCreateImage;
|
||||||
PFN_vkDestroyImage vkDestroyImage;
|
PFN_vkDestroyImage vkDestroyImage;
|
||||||
|
PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
|
||||||
#if VMA_DEDICATED_ALLOCATION
|
#if VMA_DEDICATED_ALLOCATION
|
||||||
PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
|
PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
|
||||||
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
||||||
@ -5483,9 +5484,6 @@ struct VmaBlockVector
|
|||||||
{
|
{
|
||||||
VMA_CLASS_NO_COPY(VmaBlockVector)
|
VMA_CLASS_NO_COPY(VmaBlockVector)
|
||||||
public:
|
public:
|
||||||
// Used temporarily during defragmentation.
|
|
||||||
VmaDefragmentationAlgorithm* m_pDefragmentationAlgorithm;
|
|
||||||
|
|
||||||
VmaBlockVector(
|
VmaBlockVector(
|
||||||
VmaAllocator hAllocator,
|
VmaAllocator hAllocator,
|
||||||
uint32_t memoryTypeIndex,
|
uint32_t memoryTypeIndex,
|
||||||
@ -5536,11 +5534,12 @@ public:
|
|||||||
size_t* pLostAllocationCount);
|
size_t* pLostAllocationCount);
|
||||||
VkResult CheckCorruption();
|
VkResult CheckCorruption();
|
||||||
|
|
||||||
// If m_pDefragmentationAlgorithm is not null, uses it to defragment and destroys it.
|
|
||||||
VkResult Defragment(
|
VkResult Defragment(
|
||||||
|
class VmaBlockVectorDefragmentationContext* pDefragCtx,
|
||||||
VmaDefragmentationStats* pDefragmentationStats,
|
VmaDefragmentationStats* pDefragmentationStats,
|
||||||
VkDeviceSize& maxBytesToMove,
|
VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
|
||||||
uint32_t& maxAllocationsToMove);
|
VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
|
||||||
|
VkCommandBuffer commandBuffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class VmaDefragmentationAlgorithm;
|
friend class VmaDefragmentationAlgorithm;
|
||||||
@ -5590,6 +5589,9 @@ private:
|
|||||||
|
|
||||||
VkResult ApplyDefragmentationMovesCpu(
|
VkResult ApplyDefragmentationMovesCpu(
|
||||||
const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves);
|
const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves);
|
||||||
|
VkResult ApplyDefragmentationMovesGpu(
|
||||||
|
const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
|
||||||
|
VkCommandBuffer commandBuffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Used during defragmentation. pDefragmentationStats is optional. It's in/out
|
Used during defragmentation. pDefragmentationStats is optional. It's in/out
|
||||||
@ -5752,17 +5754,73 @@ private:
|
|||||||
static bool MoveMakesSense(
|
static bool MoveMakesSense(
|
||||||
size_t dstBlockIndex, VkDeviceSize dstOffset,
|
size_t dstBlockIndex, VkDeviceSize dstOffset,
|
||||||
size_t srcBlockIndex, VkDeviceSize srcOffset);
|
size_t srcBlockIndex, VkDeviceSize srcOffset);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VmaBlockDefragmentationContext
|
||||||
|
{
|
||||||
|
VMA_CLASS_NO_COPY(VmaBlockDefragmentationContext)
|
||||||
|
public:
|
||||||
|
enum BLOCK_FLAG
|
||||||
|
{
|
||||||
|
BLOCK_FLAG_USED = 0x00000001,
|
||||||
|
};
|
||||||
|
uint32_t flags;
|
||||||
|
VkBuffer hBuffer;
|
||||||
|
|
||||||
|
VmaBlockDefragmentationContext() :
|
||||||
|
flags(0),
|
||||||
|
hBuffer(VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VmaBlockVectorDefragmentationContext
|
||||||
|
{
|
||||||
|
VMA_CLASS_NO_COPY(VmaBlockVectorDefragmentationContext)
|
||||||
|
public:
|
||||||
|
VkResult res;
|
||||||
|
VmaPool hCustomPool; // Null if not from custom pool.
|
||||||
|
VmaBlockVector* pBlockVector; // Redundant, for convenience not to fetch from m_hAllocator.
|
||||||
|
VmaDefragmentationAlgorithm* pAlgorithm; // Owner of this object.
|
||||||
|
VmaVector< VmaBlockDefragmentationContext, VmaStlAllocator<VmaBlockDefragmentationContext> > blockContexts;
|
||||||
|
|
||||||
|
VmaBlockVectorDefragmentationContext(VmaAllocator hAllocator) ;
|
||||||
|
~VmaBlockVectorDefragmentationContext();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const VmaAllocator m_hAllocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VmaDefragmentationContext_T
|
struct VmaDefragmentationContext_T
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
VMA_CLASS_NO_COPY(VmaDefragmentationContext_T)
|
VMA_CLASS_NO_COPY(VmaDefragmentationContext_T)
|
||||||
public:
|
public:
|
||||||
VmaDefragmentationContext_T();
|
VmaBlockVectorDefragmentationContext* defaultPoolContexts[VK_MAX_MEMORY_TYPES];
|
||||||
|
VmaVector< VmaBlockVectorDefragmentationContext*, VmaStlAllocator<VmaBlockVectorDefragmentationContext*> > customPoolContexts;
|
||||||
|
|
||||||
|
VmaDefragmentationContext_T(VmaAllocator hAllocator, uint32_t currFrameIndex);
|
||||||
~VmaDefragmentationContext_T();
|
~VmaDefragmentationContext_T();
|
||||||
|
|
||||||
|
void AddAllocations(
|
||||||
|
uint32_t allocationCount,
|
||||||
|
VmaAllocation* pAllocations,
|
||||||
|
VkBool32* pAllocationsChanged);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns:
|
||||||
|
VK_SUCCESS if succeeded and object can be destroyed immediately.
|
||||||
|
VK_NOT_READY if succeeded but the object must remain alive until vmaDefragmentationEnd.
|
||||||
|
Negative value if error occured and object can be destroyed immediately.
|
||||||
|
*/
|
||||||
|
VkResult Defragment(
|
||||||
|
VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
|
||||||
|
VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
|
||||||
|
VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const VmaAllocator m_hAllocator;
|
||||||
|
const uint32_t m_CurrFrameIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if VMA_RECORDING_ENABLED
|
#if VMA_RECORDING_ENABLED
|
||||||
@ -10373,7 +10431,6 @@ VmaBlockVector::VmaBlockVector(
|
|||||||
bool isCustomPool,
|
bool isCustomPool,
|
||||||
bool explicitBlockSize,
|
bool explicitBlockSize,
|
||||||
uint32_t algorithm) :
|
uint32_t algorithm) :
|
||||||
m_pDefragmentationAlgorithm(VMA_NULL),
|
|
||||||
m_hAllocator(hAllocator),
|
m_hAllocator(hAllocator),
|
||||||
m_MemoryTypeIndex(memoryTypeIndex),
|
m_MemoryTypeIndex(memoryTypeIndex),
|
||||||
m_PreferredBlockSize(preferredBlockSize),
|
m_PreferredBlockSize(preferredBlockSize),
|
||||||
@ -10392,8 +10449,6 @@ VmaBlockVector::VmaBlockVector(
|
|||||||
|
|
||||||
VmaBlockVector::~VmaBlockVector()
|
VmaBlockVector::~VmaBlockVector()
|
||||||
{
|
{
|
||||||
VMA_ASSERT(m_pDefragmentationAlgorithm == VMA_NULL);
|
|
||||||
|
|
||||||
for(size_t i = m_Blocks.size(); i--; )
|
for(size_t i = m_Blocks.size(); i--; )
|
||||||
{
|
{
|
||||||
m_Blocks[i]->Destroy(m_hAllocator);
|
m_Blocks[i]->Destroy(m_hAllocator);
|
||||||
@ -11160,6 +11215,106 @@ VkResult VmaBlockVector::ApplyDefragmentationMovesCpu(
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkResult VmaBlockVector::ApplyDefragmentationMovesGpu(
|
||||||
|
const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
|
||||||
|
VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
const size_t blockCount = m_Blocks.size();
|
||||||
|
|
||||||
|
enum BLOCK_FLAG
|
||||||
|
{
|
||||||
|
BLOCK_FLAG_USED = 0x00000001,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlockInfo
|
||||||
|
{
|
||||||
|
uint32_t flags;
|
||||||
|
VkBuffer buffer;
|
||||||
|
};
|
||||||
|
VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> >
|
||||||
|
blockInfo(blockCount, VmaStlAllocator<BlockInfo>(m_hAllocator->GetAllocationCallbacks()));
|
||||||
|
memset(blockInfo.data(), 0, blockCount * sizeof(BlockInfo));
|
||||||
|
|
||||||
|
// Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
|
||||||
|
const size_t moveCount = moves.size();
|
||||||
|
for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
|
||||||
|
{
|
||||||
|
const VmaDefragmentationMove& move = moves[moveIndex];
|
||||||
|
blockInfo[move.srcBlockIndex].flags |= BLOCK_FLAG_USED;
|
||||||
|
blockInfo[move.dstBlockIndex].flags |= BLOCK_FLAG_USED;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult res = VK_SUCCESS;
|
||||||
|
|
||||||
|
// Go over all blocks. Create and bind buffer for whole block if necessary.
|
||||||
|
{
|
||||||
|
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
|
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
|
for(size_t blockIndex = 0; (res >= 0) && (blockIndex < blockCount); ++blockIndex)
|
||||||
|
{
|
||||||
|
BlockInfo& currBlockInfo = blockInfo[blockIndex];
|
||||||
|
VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
|
||||||
|
if((currBlockInfo.flags & BLOCK_FLAG_USED) != 0)
|
||||||
|
{
|
||||||
|
bufCreateInfo.size = pBlock->m_pMetadata->GetSize();
|
||||||
|
res = (*m_hAllocator->GetVulkanFunctions().vkCreateBuffer)(
|
||||||
|
m_hAllocator->m_hDevice, &bufCreateInfo, m_hAllocator->GetAllocationCallbacks(), &currBlockInfo.buffer);
|
||||||
|
if(res == VK_SUCCESS)
|
||||||
|
{
|
||||||
|
res = (*m_hAllocator->GetVulkanFunctions().vkBindBufferMemory)(
|
||||||
|
m_hAllocator->m_hDevice, currBlockInfo.buffer, pBlock->GetDeviceMemory(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go over all moves. Post data transfer commands to command buffer.
|
||||||
|
if(res >= 0)
|
||||||
|
{
|
||||||
|
const VkDeviceSize nonCoherentAtomSize = m_hAllocator->m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
|
||||||
|
VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
|
||||||
|
|
||||||
|
for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
|
||||||
|
{
|
||||||
|
const VmaDefragmentationMove& move = moves[moveIndex];
|
||||||
|
|
||||||
|
const BlockInfo& srcBlockInfo = blockInfo[move.srcBlockIndex];
|
||||||
|
const BlockInfo& dstBlockInfo = blockInfo[move.dstBlockIndex];
|
||||||
|
|
||||||
|
VMA_ASSERT(srcBlockInfo.buffer && dstBlockInfo.buffer);
|
||||||
|
|
||||||
|
VkBufferCopy region = {
|
||||||
|
move.srcOffset,
|
||||||
|
move.dstOffset,
|
||||||
|
move.size };
|
||||||
|
(*m_hAllocator->GetVulkanFunctions().vkCmdCopyBuffer)(
|
||||||
|
commandBuffer, srcBlockInfo.buffer, dstBlockInfo.buffer, 1, ®ion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res >= VK_SUCCESS)
|
||||||
|
{
|
||||||
|
// TODO save buffers to defrag context for later destruction.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Destroy buffers.
|
||||||
|
for(size_t blockIndex = blockCount; blockIndex--; )
|
||||||
|
{
|
||||||
|
BlockInfo& currBlockInfo = blockInfo[blockIndex];
|
||||||
|
if(currBlockInfo.buffer != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
(*m_hAllocator->GetVulkanFunctions().vkDestroyBuffer)(
|
||||||
|
m_hAllocator->m_hDevice, currBlockInfo.buffer, m_hAllocator->GetAllocationCallbacks());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats)
|
void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats)
|
||||||
{
|
{
|
||||||
m_HasEmptyBlock = false;
|
m_HasEmptyBlock = false;
|
||||||
@ -11256,48 +11411,83 @@ void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
|
|||||||
#endif // #if VMA_STATS_STRING_ENABLED
|
#endif // #if VMA_STATS_STRING_ENABLED
|
||||||
|
|
||||||
VkResult VmaBlockVector::Defragment(
|
VkResult VmaBlockVector::Defragment(
|
||||||
|
class VmaBlockVectorDefragmentationContext* pDefragCtx,
|
||||||
VmaDefragmentationStats* pDefragmentationStats,
|
VmaDefragmentationStats* pDefragmentationStats,
|
||||||
VkDeviceSize& maxBytesToMove,
|
VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
|
||||||
uint32_t& maxAllocationsToMove)
|
VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
|
||||||
|
VkCommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
if(!m_pDefragmentationAlgorithm)
|
VkResult res = VK_SUCCESS;
|
||||||
|
|
||||||
|
const VkMemoryPropertyFlags memPropFlags =
|
||||||
|
m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags;
|
||||||
|
const bool canDefragmentOnCpu = maxCpuBytesToMove > 0 && maxCpuAllocationsToMove > 0 &&
|
||||||
|
(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
|
||||||
|
const bool canDefragmentOnGpu = maxGpuBytesToMove > 0 && maxGpuAllocationsToMove > 0;
|
||||||
|
|
||||||
|
// There are no options to defragment this memory type.
|
||||||
|
if(canDefragmentOnCpu || canDefragmentOnGpu)
|
||||||
{
|
{
|
||||||
return VK_SUCCESS;
|
bool defragmentOnGpu;
|
||||||
|
// There is only one option to defragment this memory types.
|
||||||
|
if(canDefragmentOnGpu != canDefragmentOnCpu)
|
||||||
|
{
|
||||||
|
defragmentOnGpu = canDefragmentOnGpu;
|
||||||
|
}
|
||||||
|
// Both options are available: Heuristics to choose the best one.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defragmentOnGpu = (memPropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 ||
|
||||||
|
m_hAllocator->IsIntegratedGpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
|
VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
|
||||||
|
|
||||||
// Defragment.
|
// Defragment.
|
||||||
|
const VkDeviceSize maxBytesToMove = defragmentOnGpu ? maxGpuBytesToMove : maxCpuBytesToMove;
|
||||||
|
const uint32_t maxAllocationsToMove = defragmentOnGpu ? maxGpuAllocationsToMove : maxCpuAllocationsToMove;
|
||||||
VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> > moves =
|
VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> > moves =
|
||||||
VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >(VmaStlAllocator<VmaDefragmentationMove>(m_hAllocator->GetAllocationCallbacks()));
|
VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >(VmaStlAllocator<VmaDefragmentationMove>(m_hAllocator->GetAllocationCallbacks()));
|
||||||
VkResult res = m_pDefragmentationAlgorithm->Defragment(moves, maxBytesToMove, maxAllocationsToMove);
|
res = pDefragCtx->pAlgorithm->Defragment(moves, maxBytesToMove, maxAllocationsToMove);
|
||||||
|
|
||||||
// Accumulate statistics.
|
// Accumulate statistics.
|
||||||
if(pDefragmentationStats != VMA_NULL)
|
if(pDefragmentationStats != VMA_NULL)
|
||||||
{
|
{
|
||||||
const VkDeviceSize bytesMoved = m_pDefragmentationAlgorithm->GetBytesMoved();
|
const VkDeviceSize bytesMoved = pDefragCtx->pAlgorithm->GetBytesMoved();
|
||||||
const uint32_t allocationsMoved = m_pDefragmentationAlgorithm->GetAllocationsMoved();
|
const uint32_t allocationsMoved = pDefragCtx->pAlgorithm->GetAllocationsMoved();
|
||||||
pDefragmentationStats->bytesMoved += bytesMoved;
|
pDefragmentationStats->bytesMoved += bytesMoved;
|
||||||
pDefragmentationStats->allocationsMoved += allocationsMoved;
|
pDefragmentationStats->allocationsMoved += allocationsMoved;
|
||||||
VMA_ASSERT(bytesMoved <= maxBytesToMove);
|
VMA_ASSERT(bytesMoved <= maxBytesToMove);
|
||||||
VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
|
VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
|
||||||
maxBytesToMove -= bytesMoved;
|
if(defragmentOnGpu)
|
||||||
maxAllocationsToMove -= allocationsMoved;
|
{
|
||||||
|
maxGpuBytesToMove -= bytesMoved;
|
||||||
|
maxGpuAllocationsToMove -= allocationsMoved;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxCpuBytesToMove -= bytesMoved;
|
||||||
|
maxCpuAllocationsToMove -= allocationsMoved;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(res >= VK_SUCCESS)
|
if(res >= VK_SUCCESS)
|
||||||
|
{
|
||||||
|
if(defragmentOnGpu)
|
||||||
|
{
|
||||||
|
res = ApplyDefragmentationMovesGpu(moves, commandBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
res = ApplyDefragmentationMovesCpu(moves);
|
res = ApplyDefragmentationMovesCpu(moves);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(res >= VK_SUCCESS)
|
if(res >= VK_SUCCESS)
|
||||||
{
|
{
|
||||||
FreeEmptyBlocks(pDefragmentationStats);
|
FreeEmptyBlocks(pDefragmentationStats);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Destroy defragmentation algorithm object.
|
|
||||||
vma_delete(m_hAllocator, m_pDefragmentationAlgorithm);
|
|
||||||
m_pDefragmentationAlgorithm = VMA_NULL;
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -11604,15 +11794,176 @@ bool VmaDefragmentationAlgorithm::MoveMakesSense(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// VmaBlockVectorDefragmentationContext
|
||||||
|
|
||||||
|
VmaBlockVectorDefragmentationContext::VmaBlockVectorDefragmentationContext(VmaAllocator hAllocator) :
|
||||||
|
res(VK_SUCCESS),
|
||||||
|
hCustomPool(VK_NULL_HANDLE),
|
||||||
|
pBlockVector(VMA_NULL),
|
||||||
|
pAlgorithm(VMA_NULL),
|
||||||
|
blockContexts(VmaStlAllocator<VmaBlockDefragmentationContext>(hAllocator->GetAllocationCallbacks())),
|
||||||
|
m_hAllocator(hAllocator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext()
|
||||||
|
{
|
||||||
|
vma_delete(m_hAllocator, pAlgorithm);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// VmaDefragmentationContext
|
// VmaDefragmentationContext
|
||||||
|
|
||||||
VmaDefragmentationContext_T::VmaDefragmentationContext_T()
|
VmaDefragmentationContext_T::VmaDefragmentationContext_T(VmaAllocator hAllocator, uint32_t currFrameIndex) :
|
||||||
|
customPoolContexts(VmaStlAllocator<VmaBlockVectorDefragmentationContext*>(hAllocator->GetAllocationCallbacks())),
|
||||||
|
m_hAllocator(hAllocator),
|
||||||
|
m_CurrFrameIndex(currFrameIndex)
|
||||||
{
|
{
|
||||||
|
memset(defaultPoolContexts, 0, sizeof(defaultPoolContexts));
|
||||||
}
|
}
|
||||||
|
|
||||||
VmaDefragmentationContext_T::~VmaDefragmentationContext_T()
|
VmaDefragmentationContext_T::~VmaDefragmentationContext_T()
|
||||||
{
|
{
|
||||||
|
for(size_t i = customPoolContexts.size(); i--; )
|
||||||
|
{
|
||||||
|
vma_delete(m_hAllocator, customPoolContexts[i]);
|
||||||
|
}
|
||||||
|
for(size_t i = m_hAllocator->m_MemProps.memoryTypeCount; i--; )
|
||||||
|
{
|
||||||
|
vma_delete(m_hAllocator, defaultPoolContexts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VmaDefragmentationContext_T::AddAllocations(
|
||||||
|
uint32_t allocationCount,
|
||||||
|
VmaAllocation* pAllocations,
|
||||||
|
VkBool32* pAllocationsChanged)
|
||||||
|
{
|
||||||
|
// Dispatch pAllocations among defragmentators. Create them when necessary.
|
||||||
|
for(size_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
|
||||||
|
{
|
||||||
|
const VmaAllocation hAlloc = pAllocations[allocIndex];
|
||||||
|
VMA_ASSERT(hAlloc);
|
||||||
|
// DedicatedAlloc cannot be defragmented.
|
||||||
|
if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
|
||||||
|
// Lost allocation cannot be defragmented.
|
||||||
|
(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
|
||||||
|
{
|
||||||
|
VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
|
||||||
|
|
||||||
|
const VmaPool hAllocPool = hAlloc->GetPool();
|
||||||
|
// This allocation belongs to custom pool.
|
||||||
|
if(hAllocPool != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
// Pools with algorithm other than default are not defragmented.
|
||||||
|
if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)
|
||||||
|
{
|
||||||
|
for(size_t i = customPoolContexts.size(); i--; )
|
||||||
|
{
|
||||||
|
if(customPoolContexts[i]->hCustomPool == hAllocPool)
|
||||||
|
{
|
||||||
|
pBlockVectorDefragCtx = customPoolContexts[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!pBlockVectorDefragCtx)
|
||||||
|
{
|
||||||
|
pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
|
||||||
|
m_hAllocator);
|
||||||
|
pBlockVectorDefragCtx->hCustomPool = hAllocPool;
|
||||||
|
pBlockVectorDefragCtx->pBlockVector = &hAllocPool->m_BlockVector;
|
||||||
|
customPoolContexts.push_back(pBlockVectorDefragCtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This allocation belongs to default pool.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
|
||||||
|
pBlockVectorDefragCtx = defaultPoolContexts[memTypeIndex];
|
||||||
|
if(!pBlockVectorDefragCtx)
|
||||||
|
{
|
||||||
|
pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
|
||||||
|
m_hAllocator);
|
||||||
|
pBlockVectorDefragCtx->pBlockVector = m_hAllocator->m_pBlockVectors[memTypeIndex];
|
||||||
|
defaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pBlockVectorDefragCtx)
|
||||||
|
{
|
||||||
|
if(!pBlockVectorDefragCtx->pAlgorithm)
|
||||||
|
{
|
||||||
|
pBlockVectorDefragCtx->pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm)(
|
||||||
|
m_hAllocator, pBlockVectorDefragCtx->pBlockVector, m_CurrFrameIndex);
|
||||||
|
}
|
||||||
|
VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ?
|
||||||
|
&pAllocationsChanged[allocIndex] : VMA_NULL;
|
||||||
|
pBlockVectorDefragCtx->pAlgorithm->AddAllocation(hAlloc, pChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult VmaDefragmentationContext_T::Defragment(
|
||||||
|
VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
|
||||||
|
VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
|
||||||
|
VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats)
|
||||||
|
{
|
||||||
|
if(pStats)
|
||||||
|
{
|
||||||
|
memset(pStats, 0, sizeof(VmaDefragmentationStats));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(commandBuffer == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
maxGpuBytesToMove = 0;
|
||||||
|
maxGpuAllocationsToMove = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult res = VK_SUCCESS;
|
||||||
|
|
||||||
|
// Process default pools.
|
||||||
|
for(uint32_t memTypeIndex = 0;
|
||||||
|
memTypeIndex < m_hAllocator->GetMemoryTypeCount() && res >= VK_SUCCESS;
|
||||||
|
++memTypeIndex)
|
||||||
|
{
|
||||||
|
if(defaultPoolContexts[memTypeIndex])
|
||||||
|
{
|
||||||
|
VMA_ASSERT(defaultPoolContexts[memTypeIndex]->pBlockVector);
|
||||||
|
VkResult localRes = defaultPoolContexts[memTypeIndex]->pBlockVector->Defragment(
|
||||||
|
defaultPoolContexts[memTypeIndex],
|
||||||
|
pStats,
|
||||||
|
maxCpuBytesToMove, maxCpuAllocationsToMove,
|
||||||
|
maxGpuBytesToMove, maxGpuAllocationsToMove,
|
||||||
|
commandBuffer);
|
||||||
|
if(localRes != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
res = localRes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process custom pools.
|
||||||
|
for(size_t customCtxIndex = 0, customCtxCount = customPoolContexts.size();
|
||||||
|
customCtxIndex < customCtxCount && res >= VK_SUCCESS;
|
||||||
|
++customCtxIndex)
|
||||||
|
{
|
||||||
|
VMA_ASSERT(customPoolContexts[customCtxIndex]->pBlockVector);
|
||||||
|
VkResult localRes = customPoolContexts[customCtxIndex]->pBlockVector->Defragment(
|
||||||
|
customPoolContexts[customCtxIndex],
|
||||||
|
pStats,
|
||||||
|
maxCpuBytesToMove, maxCpuAllocationsToMove,
|
||||||
|
maxGpuBytesToMove, maxGpuAllocationsToMove,
|
||||||
|
commandBuffer);
|
||||||
|
if(localRes != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
res = localRes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -12258,6 +12609,7 @@ void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunc
|
|||||||
m_VulkanFunctions.vkDestroyBuffer = &vkDestroyBuffer;
|
m_VulkanFunctions.vkDestroyBuffer = &vkDestroyBuffer;
|
||||||
m_VulkanFunctions.vkCreateImage = &vkCreateImage;
|
m_VulkanFunctions.vkCreateImage = &vkCreateImage;
|
||||||
m_VulkanFunctions.vkDestroyImage = &vkDestroyImage;
|
m_VulkanFunctions.vkDestroyImage = &vkDestroyImage;
|
||||||
|
m_VulkanFunctions.vkCmdCopyBuffer = &vkCmdCopyBuffer;
|
||||||
#if VMA_DEDICATED_ALLOCATION
|
#if VMA_DEDICATED_ALLOCATION
|
||||||
if(m_UseKhrDedicatedAllocation)
|
if(m_UseKhrDedicatedAllocation)
|
||||||
{
|
{
|
||||||
@ -12290,6 +12642,7 @@ void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunc
|
|||||||
VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
|
VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
|
||||||
VMA_COPY_IF_NOT_NULL(vkCreateImage);
|
VMA_COPY_IF_NOT_NULL(vkCreateImage);
|
||||||
VMA_COPY_IF_NOT_NULL(vkDestroyImage);
|
VMA_COPY_IF_NOT_NULL(vkDestroyImage);
|
||||||
|
VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer);
|
||||||
#if VMA_DEDICATED_ALLOCATION
|
#if VMA_DEDICATED_ALLOCATION
|
||||||
VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
|
VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
|
||||||
VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
|
VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
|
||||||
@ -12316,6 +12669,7 @@ void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunc
|
|||||||
VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
|
VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
|
||||||
VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
|
VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
|
||||||
VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
|
VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
|
||||||
|
VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL);
|
||||||
#if VMA_DEDICATED_ALLOCATION
|
#if VMA_DEDICATED_ALLOCATION
|
||||||
if(m_UseKhrDedicatedAllocation)
|
if(m_UseKhrDedicatedAllocation)
|
||||||
{
|
{
|
||||||
@ -12823,95 +13177,25 @@ VkResult VmaAllocator_T::DefragmentationBegin(
|
|||||||
{
|
{
|
||||||
memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
|
memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
|
||||||
}
|
}
|
||||||
if(pStats != VMA_NULL)
|
|
||||||
|
*pContext = vma_new(this, VmaDefragmentationContext_T)(
|
||||||
|
this, m_CurrentFrameIndex.load());
|
||||||
|
|
||||||
|
(*pContext)->AddAllocations(
|
||||||
|
info.allocationCount, info.pAllocations, info.pAllocationsChanged);
|
||||||
|
|
||||||
|
VkResult res = (*pContext)->Defragment(
|
||||||
|
info.maxCpuBytesToMove, info.maxCpuAllocationsToMove,
|
||||||
|
info.maxGpuBytesToMove, info.maxGpuAllocationsToMove,
|
||||||
|
info.commandBuffer, pStats);
|
||||||
|
|
||||||
|
if(res != VK_NOT_READY)
|
||||||
{
|
{
|
||||||
memset(pStats, 0, sizeof(VmaDefragmentationStats));
|
vma_delete(this, *pContext);
|
||||||
|
*pContext = VMA_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t currentFrameIndex = m_CurrentFrameIndex.load();
|
return res;
|
||||||
|
|
||||||
VmaMutexLockRead poolsLock(m_PoolsMutex, m_UseMutex);
|
|
||||||
|
|
||||||
const size_t poolCount = m_Pools.size();
|
|
||||||
const VkMemoryPropertyFlags requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
|
|
||||||
|
|
||||||
// Dispatch pAllocations among defragmentators. Create them when necessary.
|
|
||||||
for(size_t allocIndex = 0; allocIndex < info.allocationCount; ++allocIndex)
|
|
||||||
{
|
|
||||||
VmaAllocation hAlloc = info.pAllocations[allocIndex];
|
|
||||||
VMA_ASSERT(hAlloc);
|
|
||||||
const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
|
|
||||||
// DedicatedAlloc cannot be defragmented.
|
|
||||||
if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
|
|
||||||
// Only HOST_VISIBLE memory types can be defragmented.
|
|
||||||
((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags) &&
|
|
||||||
// Lost allocation cannot be defragmented.
|
|
||||||
(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
|
|
||||||
{
|
|
||||||
VmaBlockVector* pBlockVector = VMA_NULL;
|
|
||||||
|
|
||||||
const VmaPool hAllocPool = hAlloc->GetPool();
|
|
||||||
// This allocation belongs to custom pool.
|
|
||||||
if(hAllocPool != VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
// Pools with algorithm other than default are not defragmented.
|
|
||||||
if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)
|
|
||||||
{
|
|
||||||
pBlockVector = &hAllocPool->m_BlockVector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This allocation belongs to general pool.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pBlockVector = m_pBlockVectors[memTypeIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pBlockVector != VMA_NULL)
|
|
||||||
{
|
|
||||||
if(!pBlockVector->m_pDefragmentationAlgorithm)
|
|
||||||
{
|
|
||||||
pBlockVector->m_pDefragmentationAlgorithm = vma_new(this, VmaDefragmentationAlgorithm)(
|
|
||||||
this, pBlockVector, currentFrameIndex);
|
|
||||||
}
|
|
||||||
VkBool32* const pChanged = (info.pAllocationsChanged != VMA_NULL) ?
|
|
||||||
&info.pAllocationsChanged[allocIndex] : VMA_NULL;
|
|
||||||
pBlockVector->m_pDefragmentationAlgorithm->AddAllocation(hAlloc, pChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult result = VK_SUCCESS;
|
|
||||||
|
|
||||||
// Main processing: Call Defragment on block vectors.
|
|
||||||
|
|
||||||
VkDeviceSize maxBytesToMove = info.maxCpuBytesToMove;
|
|
||||||
uint32_t maxAllocationsToMove = info.maxCpuAllocationsToMove;
|
|
||||||
|
|
||||||
// Process standard memory.
|
|
||||||
for(uint32_t memTypeIndex = 0;
|
|
||||||
(memTypeIndex < GetMemoryTypeCount()) && (result == VK_SUCCESS);
|
|
||||||
++memTypeIndex)
|
|
||||||
{
|
|
||||||
// Only HOST_VISIBLE memory types can be defragmented.
|
|
||||||
if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags)
|
|
||||||
{
|
|
||||||
result = m_pBlockVectors[memTypeIndex]->Defragment(
|
|
||||||
pStats,
|
|
||||||
maxBytesToMove,
|
|
||||||
maxAllocationsToMove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process custom pools.
|
|
||||||
for(size_t poolIndex = 0; (poolIndex < poolCount) && (result == VK_SUCCESS); ++poolIndex)
|
|
||||||
{
|
|
||||||
result = m_Pools[poolIndex]->m_BlockVector.Defragment(
|
|
||||||
pStats,
|
|
||||||
maxBytesToMove,
|
|
||||||
maxAllocationsToMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult VmaAllocator_T::DefragmentationEnd(
|
VkResult VmaAllocator_T::DefragmentationEnd(
|
||||||
|
Loading…
Reference in New Issue
Block a user