Skip to content

Commit 647cf24

Browse files
VmaDefragmentationAlgorithm_Fast: Added support for memmove() of overlapping memory regions when defragmenting on CPU.
1 parent e168191 commit 647cf24

2 files changed

Lines changed: 56 additions & 15 deletions

File tree

src/Tests.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,30 @@ void TestDefragmentationSimple()
13751375
}
13761376
}
13771377

1378+
/*
1379+
Allocation that must be move to an overlapping place using memmove().
1380+
Create 2 buffers, second slightly bigger than the first. Delete first. Then defragment.
1381+
*/
1382+
{
1383+
AllocInfo allocInfo[2];
1384+
1385+
bufCreateInfo.size = BUF_SIZE;
1386+
CreateBuffer(pool, bufCreateInfo, false, allocInfo[0]);
1387+
const VkDeviceSize biggerBufSize = BUF_SIZE + BUF_SIZE / 256;
1388+
bufCreateInfo.size = biggerBufSize;
1389+
CreateBuffer(pool, bufCreateInfo, false, allocInfo[1]);
1390+
1391+
DestroyAllocation(allocInfo[0]);
1392+
1393+
VmaDefragmentationStats defragStats;
1394+
Defragment(&allocInfo[1], 1, nullptr, &defragStats);
1395+
// If this fails, it means we couldn't do memmove with overlapping regions.
1396+
TEST(defragStats.allocationsMoved == 1 && defragStats.bytesMoved > 0);
1397+
1398+
ValidateAllocationsData(&allocInfo[1], 1);
1399+
DestroyAllocation(allocInfo[1]);
1400+
}
1401+
13781402
vmaDestroyPool(g_hAllocator, pool);
13791403
}
13801404

src/vk_mem_alloc.h

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5784,7 +5784,8 @@ class VmaDefragmentationAlgorithm_Generic : public VmaDefragmentationAlgorithm
57845784
VmaDefragmentationAlgorithm_Generic(
57855785
VmaAllocator hAllocator,
57865786
VmaBlockVector* pBlockVector,
5787-
uint32_t currentFrameIndex);
5787+
uint32_t currentFrameIndex,
5788+
bool overlappingMoveSupported);
57885789
virtual ~VmaDefragmentationAlgorithm_Generic();
57895790

57905791
virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
@@ -5910,7 +5911,8 @@ class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm
59105911
VmaDefragmentationAlgorithm_Fast(
59115912
VmaAllocator hAllocator,
59125913
VmaBlockVector* pBlockVector,
5913-
uint32_t currentFrameIndex);
5914+
uint32_t currentFrameIndex,
5915+
bool overlappingMoveSupported);
59145916
virtual ~VmaDefragmentationAlgorithm_Fast();
59155917

59165918
virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) { ++m_AllocationCount; }
@@ -5930,6 +5932,8 @@ class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm
59305932
size_t origBlockIndex;
59315933
};
59325934

5935+
const bool m_OverlappingMoveSupported;
5936+
59335937
uint32_t m_AllocationCount;
59345938
bool m_AllAllocations;
59355939

@@ -5984,7 +5988,7 @@ class VmaBlockVectorDefragmentationContext
59845988
void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
59855989
void AddAll() { m_AllAllocations = true; }
59865990

5987-
void Begin();
5991+
void Begin(bool overlappingMoveSupported);
59885992

59895993
private:
59905994
const VmaAllocator m_hAllocator;
@@ -11602,7 +11606,7 @@ void VmaBlockVector::ApplyDefragmentationMovesCpu(
1160211606
}
1160311607

1160411608
// THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
11605-
memcpy(
11609+
memmove(
1160611610
reinterpret_cast<char*>(dstBlockInfo.pMappedData) + move.dstOffset,
1160711611
reinterpret_cast<char*>(srcBlockInfo.pMappedData) + move.srcOffset,
1160811612
static_cast<size_t>(move.size));
@@ -11842,13 +11846,15 @@ void VmaBlockVector::Defragment(
1184211846
m_hAllocator->IsIntegratedGpu();
1184311847
}
1184411848

11849+
bool overlappingMoveSupported = !defragmentOnGpu;
11850+
1184511851
if(m_hAllocator->m_UseMutex)
1184611852
{
1184711853
m_Mutex.LockWrite();
1184811854
pCtx->mutexLocked = true;
1184911855
}
1185011856

11851-
pCtx->Begin();
11857+
pCtx->Begin(overlappingMoveSupported);
1185211858

1185311859
// Defragment.
1185411860

@@ -12015,7 +12021,8 @@ void VmaBlockVector::AddStats(VmaStats* pStats)
1201512021
VmaDefragmentationAlgorithm_Generic::VmaDefragmentationAlgorithm_Generic(
1201612022
VmaAllocator hAllocator,
1201712023
VmaBlockVector* pBlockVector,
12018-
uint32_t currentFrameIndex) :
12024+
uint32_t currentFrameIndex,
12025+
bool overlappingMoveSupported) :
1201912026
VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
1202012027
m_AllAllocations(false),
1202112028
m_AllocationCount(0),
@@ -12307,8 +12314,10 @@ bool VmaDefragmentationAlgorithm_Generic::MoveMakesSense(
1230712314
VmaDefragmentationAlgorithm_Fast::VmaDefragmentationAlgorithm_Fast(
1230812315
VmaAllocator hAllocator,
1230912316
VmaBlockVector* pBlockVector,
12310-
uint32_t currentFrameIndex) :
12317+
uint32_t currentFrameIndex,
12318+
bool overlappingMoveSupported) :
1231112319
VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
12320+
m_OverlappingMoveSupported(overlappingMoveSupported),
1231212321
m_AllocationCount(0),
1231312322
m_AllAllocations(false),
1231412323
m_BytesMoved(0),
@@ -12396,18 +12405,26 @@ VkResult VmaDefragmentationAlgorithm_Fast::Defragment(
1239612405
// Same block
1239712406
if(dstBlockInfoIndex == srcBlockInfoIndex)
1239812407
{
12399-
// Destination and source place overlap.
12400-
if(dstAllocOffset + srcAllocSize > srcAllocOffset)
12408+
VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
12409+
12410+
const bool overlap = dstAllocOffset + srcAllocSize > srcAllocOffset;
12411+
12412+
bool skipOver = overlap;
12413+
if(overlap && m_OverlappingMoveSupported && dstAllocOffset < srcAllocOffset)
12414+
{
12415+
// If destination and source place overlap, skip if it would move it
12416+
// by only < 1/64 of its size.
12417+
skipOver = (srcAllocOffset - dstAllocOffset) * 64 < srcAllocSize;
12418+
}
12419+
12420+
if(skipOver)
1240112421
{
12402-
// Just step over this allocation.
12403-
// TODO: Support memmove() here.
1240412422
dstOffset = srcAllocOffset + srcAllocSize;
1240512423
++srcSuballocIt;
1240612424
}
1240712425
// MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
1240812426
else
1240912427
{
12410-
VMA_ASSERT(dstAllocOffset < srcAllocOffset);
1241112428
srcSuballocIt->offset = dstAllocOffset;
1241212429
srcSuballocIt->hAllocation->ChangeOffset(dstAllocOffset);
1241312430
dstOffset = dstAllocOffset + srcAllocSize;
@@ -12604,7 +12621,7 @@ void VmaBlockVectorDefragmentationContext::AddAllocation(VmaAllocation hAlloc, V
1260412621
m_Allocations.push_back(info);
1260512622
}
1260612623

12607-
void VmaBlockVectorDefragmentationContext::Begin()
12624+
void VmaBlockVectorDefragmentationContext::Begin(bool overlappingMoveSupported)
1260812625
{
1260912626
const bool allAllocations = m_AllAllocations ||
1261012627
m_Allocations.size() == m_pBlockVector->CalcAllocationCount();
@@ -12624,12 +12641,12 @@ void VmaBlockVectorDefragmentationContext::Begin()
1262412641
!m_pBlockVector->IsBufferImageGranularityConflictPossible())
1262512642
{
1262612643
m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Fast)(
12627-
m_hAllocator, m_pBlockVector, m_CurrFrameIndex);
12644+
m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
1262812645
}
1262912646
else
1263012647
{
1263112648
m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Generic)(
12632-
m_hAllocator, m_pBlockVector, m_CurrFrameIndex);
12649+
m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
1263312650
}
1263412651

1263512652
if(allAllocations)

0 commit comments

Comments
 (0)