Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions include/vk_mem_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2896,6 +2896,10 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock(
const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo,
VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock);

VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeVirtualBlock(
VmaVirtualBlock VMA_NULLABLE virtualBlock,
VkDeviceSize newSize);

/** \brief Destroys #VmaVirtualBlock object.

Please note that you should consciously handle virtual allocations that could remain unfreed in the block.
Expand Down Expand Up @@ -6998,6 +7002,7 @@ class VmaBlockMetadata
virtual ~VmaBlockMetadata() = default;

virtual void Init(VkDeviceSize size) { m_Size = size; }
virtual bool Resize(VkDeviceSize newSize) { m_Size = newSize; return true; }
bool IsVirtual() const { return m_IsVirtual; }
VkDeviceSize GetSize() const { return m_Size; }

Expand Down Expand Up @@ -7548,6 +7553,7 @@ class VmaBlockMetadata_Linear : public VmaBlockMetadata
VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }

void Init(VkDeviceSize size) override;
bool Resize(VkDeviceSize newSize) override;
bool Validate() const override;
size_t GetAllocationCount() const override;
size_t GetFreeRegionsCount() const override;
Expand Down Expand Up @@ -7663,6 +7669,18 @@ void VmaBlockMetadata_Linear::Init(VkDeviceSize size)
m_SumFreeSize = size;
}

bool VmaBlockMetadata_Linear::Resize(VkDeviceSize newSize)
{
VMA_VALIDATE(newSize > GetSize());

const VkDeviceSize extension = newSize - GetSize();
VmaBlockMetadata::Resize(newSize);

m_SumFreeSize += extension;

return true;
}

bool VmaBlockMetadata_Linear::Validate() const
{
const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
Expand Down Expand Up @@ -9165,6 +9183,7 @@ class VmaBlockMetadata_TLSF : public VmaBlockMetadata
VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; }

void Init(VkDeviceSize size) override;
bool Resize(VkDeviceSize newSize) override;
bool Validate() const override;

void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override;
Expand Down Expand Up @@ -9321,6 +9340,62 @@ void VmaBlockMetadata_TLSF::Init(VkDeviceSize size)
memset(m_FreeList, 0, m_ListsCount * sizeof(Block*));
}

bool VmaBlockMetadata_TLSF::Resize(VkDeviceSize newSize)
{
VMA_ASSERT(IsVirtual());
VMA_ASSERT(newSize > GetSize());

VkDeviceSize oldSize = GetSize();
VkDeviceSize extension = newSize - oldSize;

VmaBlockMetadata::Resize(newSize);

uint8_t newMemoryClass = SizeToMemoryClass(newSize) + uint8_t(2);
uint16_t sli = SizeToSecondIndex(newSize, newMemoryClass);
if (newMemoryClass > m_MemoryClasses)
{
uint32_t oldListsCount = m_ListsCount;
uint32_t newListsCount = (newMemoryClass == 0 ? 0 : (newMemoryClass - 1) * (1UL << SECOND_LEVEL_INDEX) + sli) + 1;

// in case of non virtual support at some point
if (IsVirtual())
newListsCount += 1UL << SECOND_LEVEL_INDEX;
else
newListsCount += 4;

Block** newFreeList = vma_new_array(GetAllocationCallbacks(), Block*, newListsCount);
VMA_ASSERT(newFreeList);

if (oldListsCount > 0)
{
memcpy(newFreeList, m_FreeList, oldListsCount * sizeof(Block*));
}

memset(newFreeList + oldListsCount, 0,
(newListsCount - oldListsCount) * sizeof(Block*));

vma_delete_array(GetAllocationCallbacks(), m_FreeList, oldListsCount);
m_FreeList = newFreeList;
m_ListsCount = newListsCount;

for (uint8_t i = m_MemoryClasses; i < newMemoryClass; ++i)
{
m_InnerIsFreeBitmap[i] = 0;
}

m_MemoryClasses = newMemoryClass;
}

m_NullBlock->size += extension;

if (!m_NullBlock->IsFree())
{
m_NullBlock->MarkFree();
}

return true;
}

bool VmaBlockMetadata_TLSF::Validate() const
{
VMA_VALIDATE(GetSumFreeSize() <= GetSize());
Expand Down Expand Up @@ -10452,6 +10527,7 @@ struct VmaVirtualBlock_T
void Free(VmaVirtualAllocation allocation) { m_Metadata->Free((VmaAllocHandle)allocation); }
void SetAllocationUserData(VmaVirtualAllocation allocation, void* userData) { m_Metadata->SetAllocationUserData((VmaAllocHandle)allocation, userData); }
void Clear() { m_Metadata->Clear(); }
void Resize(VkDeviceSize newSize) { m_Metadata->Resize(newSize); }

const VkAllocationCallbacks* GetAllocationCallbacks() const;
void GetAllocationInfo(VmaVirtualAllocation allocation, VmaVirtualAllocationInfo& outInfo);
Expand Down Expand Up @@ -17128,6 +17204,16 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock(
*/
}

VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeVirtualBlock(
VmaVirtualBlock VMA_NULLABLE virtualBlock,
VkDeviceSize newSize)
{
VMA_DEBUG_LOG("vmaResizeVirtualBlock");
VMA_DEBUG_GLOBAL_MUTEX_LOCK;
virtualBlock->Resize(newSize);
return VK_SUCCESS;
}

VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLABLE virtualBlock)
{
if(virtualBlock != VK_NULL_HANDLE)
Expand Down
73 changes: 73 additions & 0 deletions src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3379,6 +3379,78 @@ static void TestVirtualBlocks()
}
}

static void TestVirtualBlocksResizeImpl(VmaVirtualBlockCreateFlags flags)
{
VmaVirtualBlockCreateInfo blockCreateInfo = {};
blockCreateInfo.size = 3;
blockCreateInfo.flags = flags;

VmaVirtualBlock block;
TEST(vmaCreateVirtualBlock(&blockCreateInfo, &block) == VK_SUCCESS && block);

VmaVirtualAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.size = 1;
VmaVirtualAllocation allocation0 = VK_NULL_HANDLE;
VmaVirtualAllocation allocation1 = VK_NULL_HANDLE;
VmaVirtualAllocation allocation2 = VK_NULL_HANDLE;

VkDeviceSize offset;

TEST(vmaVirtualAllocate(block, &allocCreateInfo, &allocation0, &offset) == VK_SUCCESS);
TEST(allocation0 != VK_NULL_HANDLE);
TEST(vmaVirtualAllocate(block, &allocCreateInfo, &allocation1, &offset) == VK_SUCCESS);
TEST(allocation1 != VK_NULL_HANDLE);
TEST(vmaVirtualAllocate(block, &allocCreateInfo, &allocation2, &offset) == VK_SUCCESS);
TEST(allocation2 != VK_NULL_HANDLE);

allocCreateInfo.size = 2;

vmaVirtualFree(block, allocation1);

VmaVirtualAllocation oomAllocation = VK_NULL_HANDLE;
TEST(vmaVirtualAllocate(block, &allocCreateInfo, &oomAllocation, &offset) != VK_SUCCESS);
TEST(oomAllocation == VK_NULL_HANDLE);

vmaResizeVirtualBlock(block, 5);

VmaVirtualAllocation noLongerOomAllocation = VK_NULL_HANDLE;
TEST(vmaVirtualAllocate(block, &allocCreateInfo, &noLongerOomAllocation, &offset) == VK_SUCCESS);
TEST(noLongerOomAllocation != VK_NULL_HANDLE);

TEST(vmaVirtualAllocate(block, &allocCreateInfo, &oomAllocation, &offset) != VK_SUCCESS);
TEST(oomAllocation == VK_NULL_HANDLE);
}

static void TestSizeClassExtension()
{
VmaVirtualBlockCreateInfo blockCreateInfo = {};
blockCreateInfo.size = 40960;

VmaVirtualBlock block;
TEST(vmaCreateVirtualBlock(&blockCreateInfo, &block) == VK_SUCCESS && block);

VmaVirtualAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.size = 45936;

VmaVirtualAllocation allocation0 = VK_NULL_HANDLE;
VkDeviceSize offset;

TEST(vmaVirtualAllocate(block, &allocCreateInfo, &allocation0, &offset) != VK_SUCCESS);
TEST(allocation0 == VK_NULL_HANDLE);

TEST(vmaResizeVirtualBlock(block, 86896) == VK_SUCCESS);

TEST(vmaVirtualAllocate(block, &allocCreateInfo, &allocation0, &offset) == VK_SUCCESS);
TEST(allocation0 != VK_NULL_HANDLE);
}

static void TestVirtualBlocksResize()
{
TestVirtualBlocksResizeImpl(0);
TestVirtualBlocksResizeImpl(VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT);
TestSizeClassExtension();
}

static void TestVirtualBlocksAlgorithms()
{
wprintf(L"Test virtual blocks algorithms\n");
Expand Down Expand Up @@ -8861,6 +8933,7 @@ void Test()
TestJson();
TestBasics();
TestVirtualBlocks();
TestVirtualBlocksResize();
TestVirtualBlocksAlgorithms();
TestVirtualBlocksAlgorithmsBenchmark();
TestAllocationVersusResourceSize();
Expand Down