Added function vmaResizeAllocation.

Added tests: function TestResize. Bumped CSV recording file format version to 1.4.
This commit is contained in:
Adam Sawicki 2018-11-13 16:17:38 +01:00
parent 1146b45c63
commit b0c363693f
11 changed files with 530 additions and 17 deletions

View File

@ -23,7 +23,7 @@ Formats with only minor version incremented are backward compatible.
VmaReplay application supports all older versions.
Current version is:
1,3
1,4
# Configuration
@ -204,6 +204,11 @@ No parameters.
- pool : pointer
**vmaResizeAllocation** (min format version: 1.4)
- allocation : pointer
- newSize : uint64
# Data types
**bool**
@ -228,7 +233,7 @@ It should not contain end-of-line characters - results are then undefined.
# Example file
Vulkan Memory Allocator,Calls recording
1,3
1,4
Config,Begin
PhysicalDevice,apiVersion,4198477
PhysicalDevice,driverVersion,8388653

View File

@ -316,7 +316,7 @@ $(function() {
: <a class="el" href="vk__mem__alloc_8h.html#ad63b2113c0bfdbeade1cb498f5a8580d">vk_mem_alloc.h</a>
</li>
<li>VmaPoolCreateFlagBits
: <a class="el" href="vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7">vk_mem_alloc.h</a>
: <a class="el" href="vk__mem__alloc_8h.html#a8f93195158e0e2ac80ca352064e71c1f">vk_mem_alloc.h</a>
</li>
<li>VmaPoolCreateFlags
: <a class="el" href="vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a">vk_mem_alloc.h</a>
@ -336,6 +336,9 @@ $(function() {
<li>VmaRecordSettings
: <a class="el" href="vk__mem__alloc_8h.html#a0ab61e87ff6365f1d59915eadc37a9f0">vk_mem_alloc.h</a>
</li>
<li>vmaResizeAllocation()
: <a class="el" href="vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696">vk_mem_alloc.h</a>
</li>
<li>vmaSetAllocationUserData()
: <a class="el" href="vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f">vk_mem_alloc.h</a>
</li>

View File

@ -163,6 +163,9 @@ $(function() {
<li>vmaMapMemory()
: <a class="el" href="vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069">vk_mem_alloc.h</a>
</li>
<li>vmaResizeAllocation()
: <a class="el" href="vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696">vk_mem_alloc.h</a>
</li>
<li>vmaSetAllocationUserData()
: <a class="el" href="vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f">vk_mem_alloc.h</a>
</li>

View File

@ -107,6 +107,7 @@ var searchData=
['vmarecordflagbits',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'VmaRecordFlagBits():&#160;vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#ade20b626a6635ce1bf30ea53dea774e4',1,'VmaRecordFlagBits():&#160;vk_mem_alloc.h']]],
['vmarecordflags',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]],
['vmarecordsettings',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'VmaRecordSettings'],['../vk__mem__alloc_8h.html#a0ab61e87ff6365f1d59915eadc37a9f0',1,'VmaRecordSettings():&#160;vk_mem_alloc.h']]],
['vmaresizeallocation',['vmaResizeAllocation',['../vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696',1,'vk_mem_alloc.h']]],
['vmasetallocationuserdata',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]],
['vmasetcurrentframeindex',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]],
['vmastatinfo',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../vk__mem__alloc_8h.html#a810b009a788ee8aac72a25b42ffbe31c',1,'VmaStatInfo():&#160;vk_mem_alloc.h']]],

View File

@ -33,6 +33,7 @@ var searchData=
['vmainvalidateallocation',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#a0d0eb0c1102268fa9a476d12ecbe4006',1,'vk_mem_alloc.h']]],
['vmamakepoolallocationslost',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]],
['vmamapmemory',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]],
['vmaresizeallocation',['vmaResizeAllocation',['../vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696',1,'vk_mem_alloc.h']]],
['vmasetallocationuserdata',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]],
['vmasetcurrentframeindex',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]],
['vmatouchallocation',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]],

View File

@ -310,6 +310,9 @@ Functions</h2></td></tr>
<tr class="memitem:a11f0fbc034fa81a4efedd73d61ce7568"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568">vmaFreeMemory</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation)</td></tr>
<tr class="memdesc:a11f0fbc034fa81a4efedd73d61ce7568"><td class="mdescLeft">&#160;</td><td class="mdescRight">Frees memory previously allocated using <a class="el" href="vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8" title="General purpose memory allocation. ">vmaAllocateMemory()</a>, <a class="el" href="vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b">vmaAllocateMemoryForBuffer()</a>, or <a class="el" href="vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb" title="Function similar to vmaAllocateMemoryForBuffer(). ">vmaAllocateMemoryForImage()</a>. <a href="#a11f0fbc034fa81a4efedd73d61ce7568">More...</a><br /></td></tr>
<tr class="separator:a11f0fbc034fa81a4efedd73d61ce7568"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a0ff488958ca72b28e545880463cb8696"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696">vmaResizeAllocation</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation, VkDeviceSize newSize)</td></tr>
<tr class="memdesc:a0ff488958ca72b28e545880463cb8696"><td class="mdescLeft">&#160;</td><td class="mdescRight">Tries to resize an allocation in place, if there is enough free memory after it. <a href="#a0ff488958ca72b28e545880463cb8696">More...</a><br /></td></tr>
<tr class="separator:a0ff488958ca72b28e545880463cb8696"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a86dd08aba8633bfa4ad0df2e76481d8b"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b">vmaGetAllocationInfo</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
<tr class="memdesc:a86dd08aba8633bfa4ad0df2e76481d8b"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns current information about specified allocation and atomically marks it as used in current frame. <a href="#a86dd08aba8633bfa4ad0df2e76481d8b">More...</a><br /></td></tr>
<tr class="separator:a86dd08aba8633bfa4ad0df2e76481d8b"><td class="memSeparator" colspan="2">&#160;</td></tr>
@ -2364,6 +2367,50 @@ Functions</h2></td></tr>
<p>This function fails when used on allocation made in memory type that is not <code>HOST_VISIBLE</code>.</p>
<p>This function always fails when called for allocation that was created with <a class="el" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2">VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</a> flag. Such allocations cannot be mapped. </p>
</div>
</div>
<a id="a0ff488958ca72b28e545880463cb8696"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a0ff488958ca72b28e545880463cb8696">&#9670;&nbsp;</a></span>vmaResizeAllocation()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">VkResult vmaResizeAllocation </td>
<td>(</td>
<td class="paramtype"><a class="el" href="struct_vma_allocator.html">VmaAllocator</a>&#160;</td>
<td class="paramname"><em>allocator</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype"><a class="el" href="struct_vma_allocation.html">VmaAllocation</a>&#160;</td>
<td class="paramname"><em>allocation</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">VkDeviceSize&#160;</td>
<td class="paramname"><em>newSize</em>&#160;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Tries to resize an allocation in place, if there is enough free memory after it. </p>
<p>Tries to change allocation's size without moving or reallocating it. You can both shrink and grow allocation size. When growing, it succeeds only when the allocation belongs to a memory block with enough free space after it.</p>
<p>Returns <code>VK_SUCCESS</code> if allocation's size has been successfully changed. Returns <code>VK_ERROR_OUT_OF_POOL_MEMORY</code> if allocation's size could not be changed.</p>
<p>After successful call to this function, <a class="el" href="struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f" title="Size of this allocation, in bytes. ">VmaAllocationInfo::size</a> of this allocation changes. All other parameters stay the same: memory pool and type, alignment, offset, mapped pointer.</p>
<ul>
<li>Calling this function on allocation that is in lost state fails with result <code>VK_ERROR_VALIDATION_FAILED_EXT</code>.</li>
<li>Calling this function with <code>newSize</code> same as current allocation size does nothing and returns <code>VK_SUCCESS</code>.</li>
<li>Resizing dedicated allocations, as well as allocations created in pools that use linear or buddy algorithm, is not supported. The function returns <code>VK_ERROR_FEATURE_NOT_PRESENT</code> in such cases. Support may be added in the future. </li>
</ul>
</div>
</div>
<a id="af9147d31ffc11d62fc187bde283ed14f"></a>

File diff suppressed because one or more lines are too long

View File

@ -2711,6 +2711,159 @@ static void TestPool_SameSize()
vmaDestroyPool(g_hAllocator, pool);
}
static void TestResize()
{
wprintf(L"Testing vmaResizeAllocation...\n");
const VkDeviceSize KILOBYTE = 1024ull;
const VkDeviceSize MEGABYTE = KILOBYTE * 1024;
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufCreateInfo.size = 2 * MEGABYTE;
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
uint32_t memTypeIndex = UINT32_MAX;
TEST( vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &memTypeIndex) == VK_SUCCESS );
VmaPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
poolCreateInfo.blockSize = 8 * MEGABYTE;
poolCreateInfo.minBlockCount = 1;
poolCreateInfo.maxBlockCount = 1;
poolCreateInfo.memoryTypeIndex = memTypeIndex;
VmaPool pool;
TEST( vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS );
allocCreateInfo.pool = pool;
// Fill 8 MB pool with 4 * 2 MB allocations.
VmaAllocation allocs[4] = {};
VkMemoryRequirements memReq = {};
memReq.memoryTypeBits = UINT32_MAX;
memReq.alignment = 4;
memReq.size = bufCreateInfo.size;
VmaAllocationInfo allocInfo = {};
for(uint32_t i = 0; i < 4; ++i)
{
TEST( vmaAllocateMemory(g_hAllocator, &memReq, &allocCreateInfo, &allocs[i], nullptr) == VK_SUCCESS );
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 2MB
// Case: Resize to the same size always succeeds.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 2 * MEGABYTE) == VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
// Case: Shrink allocation at the end.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 1 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 1ull * 1024 * 1024);
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 1MB, free 1MB
// Case: Shrink allocation before free space.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 512 * KILOBYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 512 * KILOBYTE);
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 0.5MB, free 1.5MB
// Case: Shrink allocation before next allocation.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 1 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[0], &allocInfo);
TEST(allocInfo.size == 1 * MEGABYTE);
}
// Now it's: a0 1MB, free 1 MB, a1 2MB, a2 2MB, a3 0.5MB, free 1.5MB
// Case: Grow allocation while there is even more space available.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 1 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 1 * MEGABYTE);
}
// Now it's: a0 1MB, free 1 MB, a1 2MB, a2 2MB, a3 1MB, free 1MB
// Case: Grow allocation while there is exact amount of free space available.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 2 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[0], &allocInfo);
TEST(allocInfo.size == 2 * MEGABYTE);
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 1MB, free 1MB
// Case: Fail to grow when there is not enough free space due to next allocation.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 3 * MEGABYTE) == VK_ERROR_OUT_OF_POOL_MEMORY );
vmaGetAllocationInfo(g_hAllocator, allocs[0], &allocInfo);
TEST(allocInfo.size == 2 * MEGABYTE);
}
// Case: Fail to grow when there is not enough free space due to end of memory block.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 3 * MEGABYTE) == VK_ERROR_OUT_OF_POOL_MEMORY );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 1 * MEGABYTE);
}
for(uint32_t i = 4; i--; )
{
vmaFreeMemory(g_hAllocator, allocs[i]);
}
vmaDestroyPool(g_hAllocator, pool);
// Test dedicated allocation
{
VmaAllocationCreateInfo dedicatedAllocCreateInfo = {};
dedicatedAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
dedicatedAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
VmaAllocation dedicatedAlloc = VK_NULL_HANDLE;
TEST( vmaAllocateMemory(g_hAllocator, &memReq, &dedicatedAllocCreateInfo, &dedicatedAlloc, nullptr) == VK_SUCCESS );
// Case: Resize to the same size always succeeds.
{
TEST( vmaResizeAllocation(g_hAllocator, dedicatedAlloc, 2 * MEGABYTE) == VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, dedicatedAlloc, &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
// Case: Shrinking fails.
{
TEST( vmaResizeAllocation(g_hAllocator, dedicatedAlloc, 1 * MEGABYTE) < VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, dedicatedAlloc, &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
// Case: Growing fails.
{
TEST( vmaResizeAllocation(g_hAllocator, dedicatedAlloc, 3 * MEGABYTE) < VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, dedicatedAlloc, &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
vmaFreeMemory(g_hAllocator, dedicatedAlloc);
}
}
static bool ValidatePattern(const void* pMemory, size_t size, uint8_t pattern)
{
const uint8_t* pBytes = (const uint8_t*)pMemory;
@ -4275,7 +4428,7 @@ void Test()
// ########################################
// ########################################
BasicTestBuddyAllocator();
TestResize();
return;
}
@ -4287,6 +4440,7 @@ void Test()
#else
TestPool_SameSize();
TestHeapSizeLimit();
TestResize();
#endif
#if VMA_DEBUG_INITIALIZE_ALLOCATIONS
TestAllocationsInitialization();

View File

@ -82,6 +82,7 @@ enum class VMA_FUNCTION
TouchAllocation,
GetAllocationInfo,
MakePoolAllocationsLost,
ResizeAllocation,
Count
};
static const char* VMA_FUNCTION_NAMES[] = {
@ -104,6 +105,7 @@ static const char* VMA_FUNCTION_NAMES[] = {
"vmaTouchAllocation",
"vmaGetAllocationInfo",
"vmaMakePoolAllocationsLost",
"vmaResizeAllocation",
};
static_assert(
_countof(VMA_FUNCTION_NAMES) == (size_t)VMA_FUNCTION::Count,
@ -143,7 +145,7 @@ static size_t g_DumpStatsAfterLineNextIndex = 0;
static bool ValidateFileVersion()
{
if(GetVersionMajor(g_FileVersion) == 1 &&
GetVersionMinor(g_FileVersion) <= 3)
GetVersionMinor(g_FileVersion) <= 4)
{
return true;
}
@ -1015,6 +1017,7 @@ private:
void ExecuteTouchAllocation(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteGetAllocationInfo(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteMakePoolAllocationsLost(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteResizeAllocation(size_t lineNumber, const CsvSplit& csvSplit);
void DestroyAllocation(size_t lineNumber, const CsvSplit& csvSplit);
};
@ -1156,6 +1159,8 @@ void Player::ExecuteLine(size_t lineNumber, const StrRange& line)
ExecuteGetAllocationInfo(lineNumber, csvSplit);
else if(StrRangeEq(functionName, "vmaMakePoolAllocationsLost"))
ExecuteMakePoolAllocationsLost(lineNumber, csvSplit);
else if(StrRangeEq(functionName, "vmaResizeAllocation"))
ExecuteResizeAllocation(lineNumber, csvSplit);
else
{
if(IssueWarning())
@ -2599,6 +2604,45 @@ void Player::ExecuteMakePoolAllocationsLost(size_t lineNumber, const CsvSplit& c
}
}
void Player::ExecuteResizeAllocation(size_t lineNumber, const CsvSplit& csvSplit)
{
m_Stats.RegisterFunctionCall(VMA_FUNCTION::ResizeAllocation);
if(ValidateFunctionParameterCount(lineNumber, csvSplit, 2, false))
{
uint64_t origPtr = 0;
uint64_t newSize = 0;
if(StrRangeToPtr(csvSplit.GetRange(FIRST_PARAM_INDEX), origPtr) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 1), newSize))
{
if(origPtr != 0)
{
const auto it = m_Allocations.find(origPtr);
if(it != m_Allocations.end())
{
vmaResizeAllocation(m_Allocator, it->second.allocation, newSize);
UpdateMemStats();
}
else
{
if(IssueWarning())
{
printf("Line %zu: Allocation %llX not found.\n", lineNumber, origPtr);
}
}
}
}
else
{
if(IssueWarning())
{
printf("Line %zu: Invalid parameters for vmaResizeAllocation.\n", lineNumber);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Main functions

View File

@ -1306,6 +1306,15 @@ static void InitializeApplication()
allocatorInfo.pAllocationCallbacks = &cpuAllocationCallbacks;
}
// Uncomment to enable recording to CSV file.
/*
{
VmaRecordSettings recordSettings = {};
recordSettings.pFilePath = "VulkanSample.csv";
allocatorInfo.pRecordSettings = &recordSettings;
}
*/
ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
// Retrieve queue (doesn't need to be destroyed)

View File

@ -2374,6 +2374,31 @@ void vmaFreeMemory(
VmaAllocator allocator,
VmaAllocation allocation);
/** \brief Tries to resize an allocation in place, if there is enough free memory after it.
Tries to change allocation's size without moving or reallocating it.
You can both shrink and grow allocation size.
When growing, it succeeds only when the allocation belongs to a memory block with enough
free space after it.
Returns `VK_SUCCESS` if allocation's size has been successfully changed.
Returns `VK_ERROR_OUT_OF_POOL_MEMORY` if allocation's size could not be changed.
After successful call to this function, VmaAllocationInfo::size of this allocation changes.
All other parameters stay the same: memory pool and type, alignment, offset, mapped pointer.
- Calling this function on allocation that is in lost state fails with result `VK_ERROR_VALIDATION_FAILED_EXT`.
- Calling this function with `newSize` same as current allocation size does nothing and returns `VK_SUCCESS`.
- Resizing dedicated allocations, as well as allocations created in pools that use linear
or buddy algorithm, is not supported.
The function returns `VK_ERROR_FEATURE_NOT_PRESENT` in such cases.
Support may be added in the future.
*/
VkResult vmaResizeAllocation(
VmaAllocator allocator,
VmaAllocation allocation,
VkDeviceSize newSize);
/** \brief Returns current information about specified allocation and atomically marks it as used in current frame.
Current paramters of given allocation are returned in `pAllocationInfo`.
@ -4506,6 +4531,8 @@ public:
VmaDeviceMemoryBlock* block,
VkDeviceSize offset);
void ChangeSize(VkDeviceSize newSize);
// pMappedData not null means allocation is created with MAPPED flag.
void InitDedicatedAllocation(
uint32_t memoryTypeIndex,
@ -4766,6 +4793,9 @@ public:
virtual void Free(const VmaAllocation allocation) = 0;
virtual void FreeAtOffset(VkDeviceSize offset) = 0;
// Tries to resize (grow or shrink) space for given allocation, in place.
virtual bool ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize) { return false; }
protected:
const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
@ -4845,6 +4875,8 @@ public:
virtual void Free(const VmaAllocation allocation);
virtual void FreeAtOffset(VkDeviceSize offset);
virtual bool ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize);
private:
uint32_t m_FreeCount;
VkDeviceSize m_SumFreeSize;
@ -5597,6 +5629,10 @@ public:
VmaAllocation allocation);
void RecordFreeMemory(uint32_t frameIndex,
VmaAllocation allocation);
void RecordResizeAllocation(
uint32_t frameIndex,
VmaAllocation allocation,
VkDeviceSize newSize);
void RecordSetAllocationUserData(uint32_t frameIndex,
VmaAllocation allocation,
const void* pUserData);
@ -5763,6 +5799,10 @@ public:
// Main deallocation function.
void FreeMemory(const VmaAllocation allocation);
VkResult ResizeAllocation(
const VmaAllocation alloc,
VkDeviceSize newSize);
void CalculateStats(VmaStats* pStats);
#if VMA_STATS_STRING_ENABLED
@ -6296,6 +6336,12 @@ void VmaAllocation_T::ChangeBlockAllocation(
m_BlockAllocation.m_Offset = offset;
}
void VmaAllocation_T::ChangeSize(VkDeviceSize newSize)
{
VMA_ASSERT(newSize > 0);
m_Size = newSize;
}
VkDeviceSize VmaAllocation_T::GetOffset() const
{
switch(m_Type)
@ -7222,6 +7268,133 @@ void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
VMA_ASSERT(0 && "Not found!");
}
bool VmaBlockMetadata_Generic::ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize)
{
typedef VmaSuballocationList::iterator iter_type;
for(iter_type suballocItem = m_Suballocations.begin();
suballocItem != m_Suballocations.end();
++suballocItem)
{
VmaSuballocation& suballoc = *suballocItem;
if(suballoc.hAllocation == alloc)
{
iter_type nextItem = suballocItem;
++nextItem;
// Should have been ensured on higher level.
VMA_ASSERT(newSize != alloc->GetSize() && newSize > 0);
// Shrinking.
if(newSize < alloc->GetSize())
{
const VkDeviceSize sizeDiff = suballoc.size - newSize;
// There is next item.
if(nextItem != m_Suballocations.end())
{
// Next item is free.
if(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)
{
// Grow this next item backward.
UnregisterFreeSuballocation(nextItem);
nextItem->offset -= sizeDiff;
nextItem->size += sizeDiff;
RegisterFreeSuballocation(nextItem);
}
// Next item is not free.
else
{
// Create free item after current one.
VmaSuballocation newFreeSuballoc;
newFreeSuballoc.hAllocation = VK_NULL_HANDLE;
newFreeSuballoc.offset = suballoc.offset + newSize;
newFreeSuballoc.size = sizeDiff;
newFreeSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
iter_type newFreeSuballocIt = m_Suballocations.insert(nextItem, newFreeSuballoc);
RegisterFreeSuballocation(newFreeSuballocIt);
++m_FreeCount;
}
}
// This is the last item.
else
{
// Create free item at the end.
VmaSuballocation newFreeSuballoc;
newFreeSuballoc.hAllocation = VK_NULL_HANDLE;
newFreeSuballoc.offset = suballoc.offset + newSize;
newFreeSuballoc.size = sizeDiff;
newFreeSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
m_Suballocations.push_back(newFreeSuballoc);
iter_type newFreeSuballocIt = m_Suballocations.end();
RegisterFreeSuballocation(--newFreeSuballocIt);
++m_FreeCount;
}
suballoc.size = newSize;
m_SumFreeSize += sizeDiff;
}
// Growing.
else
{
const VkDeviceSize sizeDiff = newSize - suballoc.size;
// There is next item.
if(nextItem != m_Suballocations.end())
{
// Next item is free.
if(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)
{
// There is not enough free space, including margin.
if(nextItem->size < sizeDiff + VMA_DEBUG_MARGIN)
{
return false;
}
// There is more free space than required.
if(nextItem->size > sizeDiff)
{
// Move and shrink this next item.
UnregisterFreeSuballocation(nextItem);
nextItem->offset += sizeDiff;
nextItem->size -= sizeDiff;
RegisterFreeSuballocation(nextItem);
}
// There is exactly the amount of free space required.
else
{
// Remove this next free item.
UnregisterFreeSuballocation(nextItem);
m_Suballocations.erase(nextItem);
--m_FreeCount;
}
}
// Next item is not free - there is no space to grow.
else
{
return false;
}
}
// This is the last item - there is no space to grow.
else
{
return false;
}
suballoc.size = newSize;
m_SumFreeSize -= sizeDiff;
}
// We cannot call Validate() here because alloc object is updated to new size outside of this call.
return true;
}
}
VMA_ASSERT(0 && "Not found!");
return false;
}
bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
{
VkDeviceSize lastSize = 0;
@ -11368,7 +11541,7 @@ VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
// Write header.
fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
fprintf(m_File, "%s\n", "1,3");
fprintf(m_File, "%s\n", "1,4");
return VK_SUCCESS;
}
@ -11524,6 +11697,20 @@ void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
Flush();
}
void VmaRecorder::RecordResizeAllocation(
uint32_t frameIndex,
VmaAllocation allocation,
VkDeviceSize newSize)
{
CallParams callParams;
GetBasicParams(callParams);
VmaMutexLock lock(m_FileMutex, m_UseMutex);
fprintf(m_File, "%u,%.3f,%u,vmaResizeAllocation,%p,%llu\n", callParams.threadId, callParams.time, frameIndex,
allocation, newSize);
Flush();
}
void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
VmaAllocation allocation,
const void* pUserData)
@ -12487,6 +12674,40 @@ void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
vma_delete(this, allocation);
}
VkResult VmaAllocator_T::ResizeAllocation(
const VmaAllocation alloc,
VkDeviceSize newSize)
{
if(newSize == 0 || alloc->GetLastUseFrameIndex() == VMA_FRAME_INDEX_LOST)
{
return VK_ERROR_VALIDATION_FAILED_EXT;
}
if(newSize == alloc->GetSize())
{
return VK_SUCCESS;
}
switch(alloc->GetType())
{
case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
return VK_ERROR_FEATURE_NOT_PRESENT;
case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
if(alloc->GetBlock()->m_pMetadata->ResizeAllocation(alloc, newSize))
{
alloc->ChangeSize(newSize);
VMA_HEAVY_ASSERT(alloc->GetBlock()->m_pMetadata->Validate());
return VK_SUCCESS;
}
else
{
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
default:
VMA_ASSERT(0);
return VK_ERROR_VALIDATION_FAILED_EXT;
}
}
void VmaAllocator_T::CalculateStats(VmaStats* pStats)
{
// Initialize.
@ -13889,6 +14110,30 @@ void vmaFreeMemory(
allocator->FreeMemory(allocation);
}
VkResult vmaResizeAllocation(
VmaAllocator allocator,
VmaAllocation allocation,
VkDeviceSize newSize)
{
VMA_ASSERT(allocator && allocation);
VMA_DEBUG_LOG("vmaResizeAllocation");
VMA_DEBUG_GLOBAL_MUTEX_LOCK
#if VMA_RECORDING_ENABLED
if(allocator->GetRecorder() != VMA_NULL)
{
allocator->GetRecorder()->RecordResizeAllocation(
allocator->GetCurrentFrameIndex(),
allocation,
newSize);
}
#endif
return allocator->ResizeAllocation(allocation, newSize);
}
void vmaGetAllocationInfo(
VmaAllocator allocator,
VmaAllocation allocation,