Merge branch 'sparse_binding_example' into v2.2

# Conflicts:
#	docs/html/vk__mem__alloc_8h_source.html
#	src/Tests.cpp
#	src/VmaReplay/VmaReplay.cpp
#	src/VulkanSample.cpp
#	src/vk_mem_alloc.h
This commit is contained in:
Adam Sawicki 2018-12-10 14:45:56 +01:00
commit 71db590d7d
15 changed files with 1501 additions and 132 deletions

Binary file not shown.

View File

@ -152,6 +152,10 @@ No parameters.
- allocation : pointer
**vmaFreeMemoryPages** (min format version: 1.5)
- allocations : list of pointers
**vmaCreateLostAllocation** (min format version 1.2)
- allocation (output) : pointer
@ -170,6 +174,20 @@ No parameters.
- allocation (output) : pointer
- allocationCreateInfo.pUserData : string (may contain additional commas)
**vmaAllocateMemoryPages** (min format version 1.5)
- vkMemoryRequirements.size : uint64
- vkMemoryRequirements.alignment : uint64
- vkMemoryRequirements.memoryTypeBits : uint32
- allocationCreateInfo.flags : uint32
- allocationCreateInfo.usage : uint32
- allocationCreateInfo.requiredFlags : uint32
- allocationCreateInfo.preferredFlags : uint32
- allocationCreateInfo.memoryTypeBits : uint32
- allocationCreateInfo.pool : pointer
- allocations (output) : list of pointers
- allocationCreateInfo.pUserData : string (may contain additional commas)
**vmaAllocateMemoryForBuffer, vmaAllocateMemoryForImage** (min format version 1.2)
- vkMemoryRequirements.size : uint64

View File

@ -195,6 +195,9 @@ $(function() {
<li>vmaAllocateMemoryForImage()
: <a class="el" href="vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb">vk_mem_alloc.h</a>
</li>
<li>vmaAllocateMemoryPages()
: <a class="el" href="vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1">vk_mem_alloc.h</a>
</li>
<li>VmaAllocationCreateFlagBits
: <a class="el" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597">vk_mem_alloc.h</a>
</li>
@ -303,6 +306,9 @@ $(function() {
<li>vmaFreeMemory()
: <a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568">vk_mem_alloc.h</a>
</li>
<li>vmaFreeMemoryPages()
: <a class="el" href="vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840">vk_mem_alloc.h</a>
</li>
<li>vmaFreeStatsString()
: <a class="el" href="vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288">vk_mem_alloc.h</a>
</li>

View File

@ -73,6 +73,9 @@ $(function() {
<li>vmaAllocateMemoryForImage()
: <a class="el" href="vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb">vk_mem_alloc.h</a>
</li>
<li>vmaAllocateMemoryPages()
: <a class="el" href="vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1">vk_mem_alloc.h</a>
</li>
<li>vmaBindBufferMemory()
: <a class="el" href="vk__mem__alloc_8h.html#a6b0929b914b60cf2d45cac4bf3547470">vk_mem_alloc.h</a>
</li>
@ -142,6 +145,9 @@ $(function() {
<li>vmaFreeMemory()
: <a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568">vk_mem_alloc.h</a>
</li>
<li>vmaFreeMemoryPages()
: <a class="el" href="vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840">vk_mem_alloc.h</a>
</li>
<li>vmaFreeStatsString()
: <a class="el" href="vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288">vk_mem_alloc.h</a>
</li>

View File

@ -58,6 +58,7 @@ var searchData=
['vmaallocatememory',['vmaAllocateMemory',['../vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8',1,'vk_mem_alloc.h']]],
['vmaallocatememoryforbuffer',['vmaAllocateMemoryForBuffer',['../vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b',1,'vk_mem_alloc.h']]],
['vmaallocatememoryforimage',['vmaAllocateMemoryForImage',['../vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb',1,'vk_mem_alloc.h']]],
['vmaallocatememorypages',['vmaAllocateMemoryPages',['../vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1',1,'vk_mem_alloc.h']]],
['vmaallocation',['VmaAllocation',['../struct_vma_allocation.html',1,'']]],
['vmaallocationcreateflagbits',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597',1,'VmaAllocationCreateFlagBits():&#160;vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#abf6bf6748c7a9fe7ce5b7835c0f56af4',1,'VmaAllocationCreateFlagBits():&#160;vk_mem_alloc.h']]],
['vmaallocationcreateflags',['VmaAllocationCreateFlags',['../vk__mem__alloc_8h.html#a5225e5e11f8376f6a31a1791f3d6e817',1,'vk_mem_alloc.h']]],
@ -97,6 +98,7 @@ var searchData=
['vmafindmemorytypeindexforimageinfo',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]],
['vmaflushallocation',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#abc34ee6f021f459aff885f3758c435de',1,'vk_mem_alloc.h']]],
['vmafreememory',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568',1,'vk_mem_alloc.h']]],
['vmafreememorypages',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840',1,'vk_mem_alloc.h']]],
['vmafreestatsstring',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]],
['vmagetallocationinfo',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]],
['vmagetmemoryproperties',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]],

View File

@ -3,6 +3,7 @@ var searchData=
['vmaallocatememory',['vmaAllocateMemory',['../vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8',1,'vk_mem_alloc.h']]],
['vmaallocatememoryforbuffer',['vmaAllocateMemoryForBuffer',['../vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b',1,'vk_mem_alloc.h']]],
['vmaallocatememoryforimage',['vmaAllocateMemoryForImage',['../vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb',1,'vk_mem_alloc.h']]],
['vmaallocatememorypages',['vmaAllocateMemoryPages',['../vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1',1,'vk_mem_alloc.h']]],
['vmabindbuffermemory',['vmaBindBufferMemory',['../vk__mem__alloc_8h.html#a6b0929b914b60cf2d45cac4bf3547470',1,'vk_mem_alloc.h']]],
['vmabindimagememory',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]],
['vmabuildstatsstring',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]],
@ -26,6 +27,7 @@ var searchData=
['vmafindmemorytypeindexforimageinfo',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]],
['vmaflushallocation',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#abc34ee6f021f459aff885f3758c435de',1,'vk_mem_alloc.h']]],
['vmafreememory',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568',1,'vk_mem_alloc.h']]],
['vmafreememorypages',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840',1,'vk_mem_alloc.h']]],
['vmafreestatsstring',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]],
['vmagetallocationinfo',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]],
['vmagetmemoryproperties',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]],

View File

@ -317,6 +317,9 @@ Functions</h2></td></tr>
<tr class="memitem:abf28077dbf82d0908b8acbe8ee8dd9b8"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8">vmaAllocateMemory</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, const VkMemoryRequirements *pVkMemoryRequirements, const <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> *pCreateInfo, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocation, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
<tr class="memdesc:abf28077dbf82d0908b8acbe8ee8dd9b8"><td class="mdescLeft">&#160;</td><td class="mdescRight">General purpose memory allocation. <a href="#abf28077dbf82d0908b8acbe8ee8dd9b8">More...</a><br /></td></tr>
<tr class="separator:abf28077dbf82d0908b8acbe8ee8dd9b8"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ad37e82e492b3de38fc3f4cffd9ad0ae1"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1">vmaAllocateMemoryPages</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, const VkMemoryRequirements *pVkMemoryRequirements, const <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> *pCreateInfo, size_t allocationCount, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocations, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
<tr class="memdesc:ad37e82e492b3de38fc3f4cffd9ad0ae1"><td class="mdescLeft">&#160;</td><td class="mdescRight">General purpose memory allocation for multiple allocation objects at once. <a href="#ad37e82e492b3de38fc3f4cffd9ad0ae1">More...</a><br /></td></tr>
<tr class="separator:ad37e82e492b3de38fc3f4cffd9ad0ae1"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a7fdf64415b6c3d83c454f28d2c53df7b"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b">vmaAllocateMemoryForBuffer</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, VkBuffer buffer, const <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> *pCreateInfo, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocation, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
<tr class="separator:a7fdf64415b6c3d83c454f28d2c53df7b"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a0faa3f9e5fb233d29d1e00390650febb"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb">vmaAllocateMemoryForImage</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, VkImage image, const <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> *pCreateInfo, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocation, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
@ -325,9 +328,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:ab9e709de044c5d8476bea77a4e755840"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840">vmaFreeMemoryPages</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, size_t allocationCount, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> *pAllocations)</td></tr>
<tr class="memdesc:ab9e709de044c5d8476bea77a4e755840"><td class="mdescLeft">&#160;</td><td class="mdescRight">Frees memory and destroys multiple allocations. <a href="#ab9e709de044c5d8476bea77a4e755840">More...</a><br /></td></tr>
<tr class="separator:ab9e709de044c5d8476bea77a4e755840"><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>
@ -895,7 +898,6 @@ Functions</h2></td></tr>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597ad242a04f802e25fef0b880afe8bb0a62"></a>VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that chooses biggest possible free range for the allocation. </p>
</td></tr>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777"></a>VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that chooses first suitable free range for the allocation. </p>
<p>"First" doesn't necessarily means the one with smallest offset in memory, but rather the one that is easiest and fastest to find. </p>
</td></tr>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597a8af1210cf591784afa026d94998f735d"></a>VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that tries to minimize memory usage. </p>
</td></tr>
@ -1114,7 +1116,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<p>You should free the memory using <a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568" title="Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). ">vmaFreeMemory()</a>.</p>
<p>You should free the memory using <a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568" title="Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). ">vmaFreeMemory()</a> or <a class="el" href="vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840" title="Frees memory and destroys multiple allocations. ">vmaFreeMemoryPages()</a>.</p>
<p>It is recommended to use <a class="el" href="vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b">vmaAllocateMemoryForBuffer()</a>, <a class="el" href="vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb" title="Function similar to vmaAllocateMemoryForBuffer(). ">vmaAllocateMemoryForImage()</a>, <a class="el" href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer()</a>, <a class="el" href="vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73" title="Function similar to vmaCreateBuffer(). ">vmaCreateImage()</a> instead whenever possible. </p>
</div>
@ -1219,6 +1221,76 @@ Functions</h2></td></tr>
<p>Function similar to <a class="el" href="vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b">vmaAllocateMemoryForBuffer()</a>. </p>
</div>
</div>
<a id="ad37e82e492b3de38fc3f4cffd9ad0ae1"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ad37e82e492b3de38fc3f4cffd9ad0ae1">&#9670;&nbsp;</a></span>vmaAllocateMemoryPages()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">VkResult vmaAllocateMemoryPages </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">const VkMemoryRequirements *&#160;</td>
<td class="paramname"><em>pVkMemoryRequirements</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">const <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> *&#160;</td>
<td class="paramname"><em>pCreateInfo</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">size_t&#160;</td>
<td class="paramname"><em>allocationCount</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>pAllocations</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype"><a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *&#160;</td>
<td class="paramname"><em>pAllocationInfo</em>&#160;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td>
</tr>
</table>
</div><div class="memdoc">
<p>General purpose memory allocation for multiple allocation objects at once. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramdir"></td><td class="paramname">allocator</td><td>Allocator object. </td></tr>
<tr><td class="paramdir"></td><td class="paramname">pVkMemoryRequirements</td><td>Memory requirements for each allocation. </td></tr>
<tr><td class="paramdir"></td><td class="paramname">pCreateInfo</td><td>Creation parameters for each alloction. </td></tr>
<tr><td class="paramdir"></td><td class="paramname">allocationCount</td><td>Number of allocations to make. </td></tr>
<tr><td class="paramdir">[out]</td><td class="paramname">pAllocations</td><td>Pointer to array that will be filled with handles to created allocations. </td></tr>
<tr><td class="paramdir">[out]</td><td class="paramname">pAlocationInfo</td><td>Optional. Pointer to array that will be filled with parameters of created allocations.</td></tr>
</table>
</dd>
</dl>
<p>You should free the memory using <a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568" title="Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). ">vmaFreeMemory()</a> or <a class="el" href="vk__mem__alloc_8h.html#ab9e709de044c5d8476bea77a4e755840" title="Frees memory and destroys multiple allocations. ">vmaFreeMemoryPages()</a>.</p>
<p>Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. It is just a general purpose allocation function able to make multiple allocations at once. It may be internally optimized to be more efficient than calling <a class="el" href="vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8" title="General purpose memory allocation. ">vmaAllocateMemory()</a> <code>allocationCount</code> times.</p>
<p>All allocations are made using same parameters. All of them are created out of the same memory pool and type. If any allocation fails, all allocations already made within this function call are also freed, so that when returned result is not <code>VK_SUCCESS</code>, <code>pAllocation</code> array is always entirely filled with <code>VK_NULL_HANDLE</code>.</p>
<p>TODO Also write tests for it.</p>
<p>TODO also write test for allocation that will partially fail. </p>
</div>
</div>
<a id="a6b0929b914b60cf2d45cac4bf3547470"></a>
@ -2200,6 +2272,46 @@ Functions</h2></td></tr>
</div><div class="memdoc">
<p>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>. </p>
<p>Passing <code>VK_NULL_HANDLE</code> as <code>allocation</code> is valid. Such function call is just skipped. </p>
</div>
</div>
<a id="ab9e709de044c5d8476bea77a4e755840"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ab9e709de044c5d8476bea77a4e755840">&#9670;&nbsp;</a></span>vmaFreeMemoryPages()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">void vmaFreeMemoryPages </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">size_t&#160;</td>
<td class="paramname"><em>allocationCount</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>pAllocations</em>&#160;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Frees memory and destroys multiple allocations. </p>
<p>Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. It is just a general purpose function to free memory and destroy allocations made using e.g. <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#ad37e82e492b3de38fc3f4cffd9ad0ae1" title="General purpose memory allocation for multiple allocation objects at once. ">vmaAllocateMemoryPages()</a> and other functions. It may be internally optimized to be more efficient than calling <a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568" title="Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). ">vmaFreeMemory()</a> <code>allocationCount</code> times.</p>
<p>Allocations in <code>pAllocations</code> array can come from any memory pools and types. Passing <code>VK_NULL_HANDLE</code> as elements of <code>pAllocations</code> array is valid. Such entries are just skipped.</p>
<p>TODO Also write tests for it. </p>
</div>
</div>
@ -2548,50 +2660,6 @@ 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>

View File

@ -1,3 +1,4 @@
%VULKAN_SDK%/Bin32/glslangValidator.exe -V -o ../../bin/Shader.vert.spv Shader.vert
%VULKAN_SDK%/Bin32/glslangValidator.exe -V -o ../../bin/Shader.frag.spv Shader.frag
%VULKAN_SDK%/Bin32/glslangValidator.exe -V -o ../../bin/SparseBindingTest.comp.spv SparseBindingTest.comp
pause

View File

@ -0,0 +1,44 @@
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// 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
// THE SOFTWARE.
//
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(binding=0) uniform sampler2D img;
layout(binding=1) buffer buf
{
uint bufValues[];
};
void main()
{
ivec2 xy = ivec2(bufValues[gl_GlobalInvocationID.x * 3],
bufValues[gl_GlobalInvocationID.x * 3 + 1]);
vec4 color = texture(img, xy);
bufValues[gl_GlobalInvocationID.x * 3 + 2] =
uint(color.r * 255.0) << 24 |
uint(color.g * 255.0) << 16 |
uint(color.b * 255.0) << 8 |
uint(color.a * 255.0);
}

571
src/SparseBindingTest.cpp Normal file
View File

@ -0,0 +1,571 @@
#include "Common.h"
#include "SparseBindingTest.h"
#ifdef _WIN32
////////////////////////////////////////////////////////////////////////////////
// External imports
extern VkDevice g_hDevice;
extern VmaAllocator g_hAllocator;
extern uint32_t g_FrameIndex;
extern bool g_SparseBindingEnabled;
extern VkQueue g_hSparseBindingQueue;
extern VkFence g_ImmediateFence;
extern VkCommandBuffer g_hTemporaryCommandBuffer;
void BeginSingleTimeCommands();
void EndSingleTimeCommands();
void SaveAllocatorStatsToFile(const wchar_t* filePath);
void LoadShader(std::vector<char>& out, const char* fileName);
////////////////////////////////////////////////////////////////////////////////
// Class definitions
static uint32_t CalculateMipMapCount(uint32_t width, uint32_t height, uint32_t depth)
{
uint32_t mipMapCount = 1;
while(width > 1 || height > 1 || depth > 1)
{
++mipMapCount;
width /= 2;
height /= 2;
depth /= 2;
}
return mipMapCount;
}
class BaseImage
{
public:
virtual void Init(RandomNumberGenerator& rand) = 0;
virtual ~BaseImage();
const VkImageCreateInfo& GetCreateInfo() const { return m_CreateInfo; }
void TestContent(RandomNumberGenerator& rand);
protected:
VkImageCreateInfo m_CreateInfo = {};
VkImage m_Image = VK_NULL_HANDLE;
void FillImageCreateInfo(RandomNumberGenerator& rand);
void UploadContent();
void ValidateContent(RandomNumberGenerator& rand);
};
class TraditionalImage : public BaseImage
{
public:
virtual void Init(RandomNumberGenerator& rand);
virtual ~TraditionalImage();
private:
VmaAllocation m_Allocation = VK_NULL_HANDLE;
};
class SparseBindingImage : public BaseImage
{
public:
virtual void Init(RandomNumberGenerator& rand);
virtual ~SparseBindingImage();
private:
std::vector<VmaAllocation> m_Allocations;
};
////////////////////////////////////////////////////////////////////////////////
// class BaseImage
BaseImage::~BaseImage()
{
if(m_Image)
{
vkDestroyImage(g_hDevice, m_Image, nullptr);
}
}
void BaseImage::TestContent(RandomNumberGenerator& rand)
{
printf("Validating content of %u x %u texture...\n",
m_CreateInfo.extent.width, m_CreateInfo.extent.height);
UploadContent();
ValidateContent(rand);
}
void BaseImage::FillImageCreateInfo(RandomNumberGenerator& rand)
{
constexpr uint32_t imageSizeMin = 8;
constexpr uint32_t imageSizeMax = 2048;
const bool useMipMaps = rand.Generate() % 2 != 0;
ZeroMemory(&m_CreateInfo, sizeof(m_CreateInfo));
m_CreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
m_CreateInfo.imageType = VK_IMAGE_TYPE_2D;
m_CreateInfo.extent.width = rand.Generate() % (imageSizeMax - imageSizeMin) + imageSizeMin;
m_CreateInfo.extent.height = rand.Generate() % (imageSizeMax - imageSizeMin) + imageSizeMin;
m_CreateInfo.extent.depth = 1;
m_CreateInfo.mipLevels = useMipMaps ?
CalculateMipMapCount(m_CreateInfo.extent.width, m_CreateInfo.extent.height, m_CreateInfo.extent.depth) : 1;
m_CreateInfo.arrayLayers = 1;
m_CreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
m_CreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
m_CreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_CreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
m_CreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
m_CreateInfo.flags = 0;
}
void BaseImage::UploadContent()
{
VkBufferCreateInfo srcBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
srcBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
srcBufCreateInfo.size = 4 * m_CreateInfo.extent.width * m_CreateInfo.extent.height;
VmaAllocationCreateInfo srcBufAllocCreateInfo = {};
srcBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
srcBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
VkBuffer srcBuf = nullptr;
VmaAllocation srcBufAlloc = nullptr;
VmaAllocationInfo srcAllocInfo = {};
TEST( vmaCreateBuffer(g_hAllocator, &srcBufCreateInfo, &srcBufAllocCreateInfo, &srcBuf, &srcBufAlloc, &srcAllocInfo) == VK_SUCCESS );
// Fill texels with: r = x % 255, g = u % 255, b = 13, a = 25
uint32_t* srcBufPtr = (uint32_t*)srcAllocInfo.pMappedData;
for(uint32_t y = 0, sizeY = m_CreateInfo.extent.height; y < sizeY; ++y)
{
for(uint32_t x = 0, sizeX = m_CreateInfo.extent.width; x < sizeX; ++x, ++srcBufPtr)
{
const uint8_t r = (uint8_t)x;
const uint8_t g = (uint8_t)y;
const uint8_t b = 13;
const uint8_t a = 25;
*srcBufPtr = (uint32_t)r << 24 | (uint32_t)g << 16 |
(uint32_t)b << 8 | (uint32_t)a;
}
}
BeginSingleTimeCommands();
// Barrier undefined to transfer dst.
{
VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = m_Image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.layerCount = 1;
barrier.subresourceRange.levelCount = 1;
vkCmdPipelineBarrier(g_hTemporaryCommandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask
VK_PIPELINE_STAGE_TRANSFER_BIT, // dstStageMask
0, // dependencyFlags
0, nullptr, // memoryBarriers
0, nullptr, // bufferMemoryBarriers
1, &barrier); // imageMemoryBarriers
}
// CopyBufferToImage
{
VkBufferImageCopy region = {};
region.bufferOffset = 0;
region.bufferRowLength = 0; // Zeros mean tightly packed.
region.bufferImageHeight = 0; // Zeros mean tightly packed.
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = m_CreateInfo.extent;
vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, srcBuf, m_Image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
// Barrier transfer dst to fragment shader read only.
{
VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = m_Image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.layerCount = 1;
barrier.subresourceRange.levelCount = 1;
vkCmdPipelineBarrier(g_hTemporaryCommandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // dstStageMask
0, // dependencyFlags
0, nullptr, // memoryBarriers
0, nullptr, // bufferMemoryBarriers
1, &barrier); // imageMemoryBarriers
}
EndSingleTimeCommands();
vmaDestroyBuffer(g_hAllocator, srcBuf, srcBufAlloc);
}
void BaseImage::ValidateContent(RandomNumberGenerator& rand)
{
/*
dstBuf has following layout:
For each of texels to be sampled, [0..valueCount):
struct {
in uint32_t pixelX;
in uint32_t pixelY;
out uint32_t pixelColor;
}
*/
const uint32_t valueCount = 128;
VkBufferCreateInfo dstBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
dstBufCreateInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
dstBufCreateInfo.size = valueCount * sizeof(uint32_t) * 3;
VmaAllocationCreateInfo dstBufAllocCreateInfo = {};
dstBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
dstBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
VkBuffer dstBuf = nullptr;
VmaAllocation dstBufAlloc = nullptr;
VmaAllocationInfo dstBufAllocInfo = {};
TEST( vmaCreateBuffer(g_hAllocator, &dstBufCreateInfo, &dstBufAllocCreateInfo, &dstBuf, &dstBufAlloc, &dstBufAllocInfo) == VK_SUCCESS );
// Fill dstBuf input data.
{
uint32_t* dstBufContent = (uint32_t*)dstBufAllocInfo.pMappedData;
for(uint32_t i = 0; i < valueCount; ++i)
{
const uint32_t x = rand.Generate() % m_CreateInfo.extent.width;
const uint32_t y = rand.Generate() % m_CreateInfo.extent.height;
dstBufContent[i * 3 ] = x;
dstBufContent[i * 3 + 1] = y;
dstBufContent[i * 3 + 2] = 0;
}
}
VkSamplerCreateInfo samplerCreateInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samplerCreateInfo.magFilter = VK_FILTER_NEAREST;
samplerCreateInfo.minFilter = VK_FILTER_NEAREST;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCreateInfo.unnormalizedCoordinates = VK_TRUE;
VkSampler sampler = nullptr;
TEST( vkCreateSampler( g_hDevice, &samplerCreateInfo, nullptr, &sampler) == VK_SUCCESS );
VkDescriptorSetLayoutBinding bindings[2] = {};
bindings[0].binding = 0;
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[0].descriptorCount = 1;
bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
bindings[0].pImmutableSamplers = &sampler;
bindings[1].binding = 1;
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
bindings[1].descriptorCount = 1;
bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
VkDescriptorSetLayoutCreateInfo descSetLayoutCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
descSetLayoutCreateInfo.bindingCount = 2;
descSetLayoutCreateInfo.pBindings = bindings;
VkDescriptorSetLayout descSetLayout = nullptr;
TEST( vkCreateDescriptorSetLayout(g_hDevice, &descSetLayoutCreateInfo, nullptr, &descSetLayout) == VK_SUCCESS );
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pipelineLayoutCreateInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.pSetLayouts = &descSetLayout;
VkPipelineLayout pipelineLayout = nullptr;
TEST( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout) == VK_SUCCESS );
std::vector<char> shaderCode;
LoadShader(shaderCode, "SparseBindingTest.comp.spv");
VkShaderModuleCreateInfo shaderModuleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
shaderModuleCreateInfo.codeSize = shaderCode.size();
shaderModuleCreateInfo.pCode = (const uint32_t*)shaderCode.data();
VkShaderModule shaderModule = nullptr;
TEST( vkCreateShaderModule(g_hDevice, &shaderModuleCreateInfo, nullptr, &shaderModule) == VK_SUCCESS );
VkComputePipelineCreateInfo pipelineCreateInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
pipelineCreateInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
pipelineCreateInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
pipelineCreateInfo.stage.module = shaderModule;
pipelineCreateInfo.stage.pName = "main";
pipelineCreateInfo.layout = pipelineLayout;
VkPipeline pipeline = nullptr;
TEST( vkCreateComputePipelines(g_hDevice, nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline) == VK_SUCCESS );
VkDescriptorPoolSize poolSizes[2] = {};
poolSizes[0].type = bindings[0].descriptorType;
poolSizes[0].descriptorCount = bindings[0].descriptorCount;
poolSizes[1].type = bindings[1].descriptorType;
poolSizes[1].descriptorCount = bindings[1].descriptorCount;
VkDescriptorPoolCreateInfo descPoolCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
descPoolCreateInfo.maxSets = 1;
descPoolCreateInfo.poolSizeCount = 2;
descPoolCreateInfo.pPoolSizes = poolSizes;
VkDescriptorPool descPool = nullptr;
TEST( vkCreateDescriptorPool(g_hDevice, &descPoolCreateInfo, nullptr, &descPool) == VK_SUCCESS );
VkDescriptorSetAllocateInfo descSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
descSetAllocInfo.descriptorPool = descPool;
descSetAllocInfo.descriptorSetCount = 1;
descSetAllocInfo.pSetLayouts = &descSetLayout;
VkDescriptorSet descSet = nullptr;
TEST( vkAllocateDescriptorSets(g_hDevice, &descSetAllocInfo, &descSet) == VK_SUCCESS );
VkImageViewCreateInfo imageViewCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
imageViewCreateInfo.image = m_Image;
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCreateInfo.format = m_CreateInfo.format;
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewCreateInfo.subresourceRange.layerCount = 1;
imageViewCreateInfo.subresourceRange.levelCount = 1;
VkImageView imageView = nullptr;
TEST( vkCreateImageView(g_hDevice, &imageViewCreateInfo, nullptr, &imageView) == VK_SUCCESS );
VkDescriptorImageInfo descImageInfo = {};
descImageInfo.imageView = imageView;
descImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkDescriptorBufferInfo descBufferInfo = {};
descBufferInfo.buffer = dstBuf;
descBufferInfo.offset = 0;
descBufferInfo.range = VK_WHOLE_SIZE;
VkWriteDescriptorSet descWrites[2] = {};
descWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descWrites[0].dstSet = descSet;
descWrites[0].dstBinding = bindings[0].binding;
descWrites[0].dstArrayElement = 0;
descWrites[0].descriptorCount = 1;
descWrites[0].descriptorType = bindings[0].descriptorType;
descWrites[0].pImageInfo = &descImageInfo;
descWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descWrites[1].dstSet = descSet;
descWrites[1].dstBinding = bindings[1].binding;
descWrites[1].dstArrayElement = 0;
descWrites[1].descriptorCount = 1;
descWrites[1].descriptorType = bindings[1].descriptorType;
descWrites[1].pBufferInfo = &descBufferInfo;
vkUpdateDescriptorSets(g_hDevice, 2, descWrites, 0, nullptr);
BeginSingleTimeCommands();
vkCmdBindPipeline(g_hTemporaryCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
vkCmdBindDescriptorSets(g_hTemporaryCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, &descSet, 0, nullptr);
vkCmdDispatch(g_hTemporaryCommandBuffer, valueCount, 1, 1);
EndSingleTimeCommands();
// Validate dstBuf output data.
{
const uint32_t* dstBufContent = (const uint32_t*)dstBufAllocInfo.pMappedData;
for(uint32_t i = 0; i < valueCount; ++i)
{
const uint32_t x = dstBufContent[i * 3 ];
const uint32_t y = dstBufContent[i * 3 + 1];
const uint32_t color = dstBufContent[i * 3 + 2];
const uint8_t a = (uint8_t)(color >> 24);
const uint8_t b = (uint8_t)(color >> 16);
const uint8_t g = (uint8_t)(color >> 8);
const uint8_t r = (uint8_t)color;
TEST(r == (uint8_t)x && g == (uint8_t)y && b == 13 && a == 25);
}
}
vkDestroyImageView(g_hDevice, imageView, nullptr);
vkDestroyDescriptorPool(g_hDevice, descPool, nullptr);
vmaDestroyBuffer(g_hAllocator, dstBuf, dstBufAlloc);
vkDestroyPipeline(g_hDevice, pipeline, nullptr);
vkDestroyShaderModule(g_hDevice, shaderModule, nullptr);
vkDestroyPipelineLayout(g_hDevice, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(g_hDevice, descSetLayout, nullptr);
vkDestroySampler(g_hDevice, sampler, nullptr);
}
////////////////////////////////////////////////////////////////////////////////
// class TraditionalImage
void TraditionalImage::Init(RandomNumberGenerator& rand)
{
FillImageCreateInfo(rand);
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
// Default BEST_FIT is clearly better.
//allocCreateInfo.flags |= VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT;
ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &m_CreateInfo, &allocCreateInfo,
&m_Image, &m_Allocation, nullptr) );
}
TraditionalImage::~TraditionalImage()
{
if(m_Allocation)
{
vmaFreeMemory(g_hAllocator, m_Allocation);
}
}
////////////////////////////////////////////////////////////////////////////////
// class SparseBindingImage
void SparseBindingImage::Init(RandomNumberGenerator& rand)
{
assert(g_SparseBindingEnabled && g_hSparseBindingQueue);
// Create image.
FillImageCreateInfo(rand);
m_CreateInfo.flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
ERR_GUARD_VULKAN( vkCreateImage(g_hDevice, &m_CreateInfo, nullptr, &m_Image) );
// Get memory requirements.
VkMemoryRequirements imageMemReq;
vkGetImageMemoryRequirements(g_hDevice, m_Image, &imageMemReq);
// This is just to silence validation layer warning.
// But it doesn't help. Looks like a bug in Vulkan validation layers.
// See: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/364
uint32_t sparseMemReqCount = 0;
vkGetImageSparseMemoryRequirements(g_hDevice, m_Image, &sparseMemReqCount, nullptr);
TEST(sparseMemReqCount <= 8);
VkSparseImageMemoryRequirements sparseMemReq[8];
vkGetImageSparseMemoryRequirements(g_hDevice, m_Image, &sparseMemReqCount, sparseMemReq);
// According to Vulkan specification, for sparse resources memReq.alignment is also page size.
const VkDeviceSize pageSize = imageMemReq.alignment;
const uint32_t pageCount = (uint32_t)ceil_div<VkDeviceSize>(imageMemReq.size, pageSize);
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VkMemoryRequirements pageMemReq = imageMemReq;
pageMemReq.size = pageSize;
// Allocate and bind memory pages.
m_Allocations.resize(pageCount);
std::fill(m_Allocations.begin(), m_Allocations.end(), nullptr);
std::vector<VkSparseMemoryBind> binds{pageCount};
std::vector<VmaAllocationInfo> allocInfo{pageCount};
ERR_GUARD_VULKAN( vmaAllocateMemoryPages(g_hAllocator, &pageMemReq, &allocCreateInfo, pageCount, m_Allocations.data(), allocInfo.data()) );
for(uint32_t i = 0; i < pageCount; ++i)
{
binds[i] = {};
binds[i].resourceOffset = pageSize * i;
binds[i].size = pageSize;
binds[i].memory = allocInfo[i].deviceMemory;
binds[i].memoryOffset = allocInfo[i].offset;
}
VkSparseImageOpaqueMemoryBindInfo imageBindInfo;
imageBindInfo.image = m_Image;
imageBindInfo.bindCount = pageCount;
imageBindInfo.pBinds = binds.data();
VkBindSparseInfo bindSparseInfo = { VK_STRUCTURE_TYPE_BIND_SPARSE_INFO };
bindSparseInfo.pImageOpaqueBinds = &imageBindInfo;
bindSparseInfo.imageOpaqueBindCount = 1;
ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &g_ImmediateFence) );
ERR_GUARD_VULKAN( vkQueueBindSparse(g_hSparseBindingQueue, 1, &bindSparseInfo, g_ImmediateFence) );
ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &g_ImmediateFence, VK_TRUE, UINT64_MAX) );
}
SparseBindingImage::~SparseBindingImage()
{
vmaFreeMemoryPages(g_hAllocator, m_Allocations.size(), m_Allocations.data());
}
////////////////////////////////////////////////////////////////////////////////
// Private functions
////////////////////////////////////////////////////////////////////////////////
// Public functions
void TestSparseBinding()
{
struct ImageInfo
{
std::unique_ptr<BaseImage> image;
uint32_t endFrame;
};
std::vector<ImageInfo> images;
constexpr uint32_t frameCount = 1000;
constexpr uint32_t imageLifeFramesMin = 1;
constexpr uint32_t imageLifeFramesMax = 400;
RandomNumberGenerator rand(4652467);
for(uint32_t i = 0; i < frameCount; ++i)
{
// Bump frame index.
++g_FrameIndex;
vmaSetCurrentFrameIndex(g_hAllocator, g_FrameIndex);
// Create one new, random image.
ImageInfo imageInfo;
//imageInfo.image = std::make_unique<TraditionalImage>();
imageInfo.image = std::make_unique<SparseBindingImage>();
imageInfo.image->Init(rand);
imageInfo.endFrame = g_FrameIndex + rand.Generate() % (imageLifeFramesMax - imageLifeFramesMin) + imageLifeFramesMin;
images.push_back(std::move(imageInfo));
// Delete all images that expired.
for(size_t i = images.size(); i--; )
{
if(g_FrameIndex >= images[i].endFrame)
{
images.erase(images.begin() + i);
}
}
}
SaveAllocatorStatsToFile(L"SparseBindingTest.json");
// Choose biggest image. Test uploading and sampling.
BaseImage* biggestImage = nullptr;
for(size_t i = 0, count = images.size(); i < count; ++i)
{
if(!biggestImage ||
images[i].image->GetCreateInfo().extent.width * images[i].image->GetCreateInfo().extent.height >
biggestImage->GetCreateInfo().extent.width * biggestImage->GetCreateInfo().extent.height)
{
biggestImage = images[i].image.get();
}
}
assert(biggestImage);
biggestImage->TestContent(rand);
// Free remaining images.
images.clear();
}
#endif // #ifdef _WIN32

7
src/SparseBindingTest.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#ifdef _WIN32
void TestSparseBinding();
#endif // #ifdef _WIN32

View File

@ -143,7 +143,7 @@ struct PoolTestResult
static const uint32_t IMAGE_BYTES_PER_PIXEL = 1;
static uint32_t g_FrameIndex = 0;
uint32_t g_FrameIndex = 0;
struct BufferInfo
{
@ -639,7 +639,7 @@ VkResult MainTest(Result& outResult, const Config& config)
return res;
}
static void SaveAllocatorStatsToFile(const wchar_t* filePath)
void SaveAllocatorStatsToFile(const wchar_t* filePath)
{
char* stats;
vmaBuildStatsString(g_hAllocator, &stats, VK_TRUE);
@ -5010,6 +5010,103 @@ static void BasicTestBuddyAllocator()
vmaDestroyPool(g_hAllocator, pool);
}
static void BasicTestAllocatePages()
{
wprintf(L"Basic test allocate pages\n");
RandomNumberGenerator rand{765461};
VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
sampleBufCreateInfo.size = 1024; // Whatever.
sampleBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo sampleAllocCreateInfo = {};
sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
VmaPoolCreateInfo poolCreateInfo = {};
VkResult res = vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, &sampleBufCreateInfo, &sampleAllocCreateInfo, &poolCreateInfo.memoryTypeIndex);
TEST(res == VK_SUCCESS);
// 1 block of 1 MB.
poolCreateInfo.blockSize = 1024 * 1024;
poolCreateInfo.minBlockCount = poolCreateInfo.maxBlockCount = 1;
// Create pool.
VmaPool pool = nullptr;
res = vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool);
TEST(res == VK_SUCCESS);
// Make 100 allocations of 4 KB - they should fit into the pool.
VkMemoryRequirements memReq;
memReq.memoryTypeBits = UINT32_MAX;
memReq.alignment = 4 * 1024;
memReq.size = 4 * 1024;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
allocCreateInfo.pool = pool;
constexpr uint32_t allocCount = 100;
std::vector<VmaAllocation> alloc{allocCount};
std::vector<VmaAllocationInfo> allocInfo{allocCount};
res = vmaAllocateMemoryPages(g_hAllocator, &memReq, &allocCreateInfo, allocCount, alloc.data(), allocInfo.data());
TEST(res == VK_SUCCESS);
for(uint32_t i = 0; i < allocCount; ++i)
{
TEST(alloc[i] != VK_NULL_HANDLE &&
allocInfo[i].pMappedData != nullptr &&
allocInfo[i].deviceMemory == allocInfo[0].deviceMemory &&
allocInfo[i].memoryType == allocInfo[0].memoryType);
}
// Free the allocations.
vmaFreeMemoryPages(g_hAllocator, allocCount, alloc.data());
std::fill(alloc.begin(), alloc.end(), nullptr);
std::fill(allocInfo.begin(), allocInfo.end(), VmaAllocationInfo{});
// Try to make 100 allocations of 100 KB. This call should fail due to not enough memory.
// Also test optional allocationInfo = null.
memReq.size = 100 * 1024;
res = vmaAllocateMemoryPages(g_hAllocator, &memReq, &allocCreateInfo, allocCount, alloc.data(), nullptr);
TEST(res != VK_SUCCESS);
TEST(std::find_if(alloc.begin(), alloc.end(), [](VmaAllocation alloc){ return alloc != VK_NULL_HANDLE; }) == alloc.end());
// Make 100 allocations of 4 KB, but with required alignment of 128 KB. This should also fail.
memReq.size = 4 * 1024;
memReq.alignment = 128 * 1024;
res = vmaAllocateMemoryPages(g_hAllocator, &memReq, &allocCreateInfo, allocCount, alloc.data(), allocInfo.data());
TEST(res != VK_SUCCESS);
// Make 100 dedicated allocations of 4 KB.
memReq.alignment = 4 * 1024;
memReq.size = 4 * 1024;
VmaAllocationCreateInfo dedicatedAllocCreateInfo = {};
dedicatedAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
dedicatedAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
res = vmaAllocateMemoryPages(g_hAllocator, &memReq, &dedicatedAllocCreateInfo, allocCount, alloc.data(), allocInfo.data());
TEST(res == VK_SUCCESS);
for(uint32_t i = 0; i < allocCount; ++i)
{
TEST(alloc[i] != VK_NULL_HANDLE &&
allocInfo[i].pMappedData != nullptr &&
allocInfo[i].memoryType == allocInfo[0].memoryType &&
allocInfo[i].offset == 0);
if(i > 0)
{
TEST(allocInfo[i].deviceMemory != allocInfo[0].deviceMemory);
}
}
// Free the allocations.
vmaFreeMemoryPages(g_hAllocator, allocCount, alloc.data());
std::fill(alloc.begin(), alloc.end(), nullptr);
std::fill(allocInfo.begin(), allocInfo.end(), VmaAllocationInfo{});
vmaDestroyPool(g_hAllocator, pool);
}
// Test the testing environment.
static void TestGpuData()
{
@ -5083,6 +5180,7 @@ void Test()
TestLinearAllocatorMultiBlock();
BasicTestBuddyAllocator();
BasicTestAllocatePages();
{
FILE* file;

View File

@ -73,8 +73,10 @@ enum class VMA_FUNCTION
CreateImage,
DestroyImage,
FreeMemory,
FreeMemoryPages,
CreateLostAllocation,
AllocateMemory,
AllocateMemoryPages,
AllocateMemoryForBuffer,
AllocateMemoryForImage,
MapMemory,
@ -98,8 +100,10 @@ static const char* VMA_FUNCTION_NAMES[] = {
"vmaCreateImage",
"vmaDestroyImage",
"vmaFreeMemory",
"vmaFreeMemoryPages",
"vmaCreateLostAllocation",
"vmaAllocateMemory",
"vmaAllocateMemoryPages",
"vmaAllocateMemoryForBuffer",
"vmaAllocateMemoryForImage",
"vmaMapMemory",
@ -1023,8 +1027,10 @@ private:
void ExecuteCreateImage(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteDestroyImage(size_t lineNumber, const CsvSplit& csvSplit) { m_Stats.RegisterFunctionCall(VMA_FUNCTION::DestroyImage); DestroyAllocation(lineNumber, csvSplit, "vmaDestroyImage"); }
void ExecuteFreeMemory(size_t lineNumber, const CsvSplit& csvSplit) { m_Stats.RegisterFunctionCall(VMA_FUNCTION::FreeMemory); DestroyAllocation(lineNumber, csvSplit, "vmaFreeMemory"); }
void ExecuteFreeMemoryPages(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteCreateLostAllocation(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteAllocateMemory(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteAllocateMemoryPages(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteAllocateMemoryForBufferOrImage(size_t lineNumber, const CsvSplit& csvSplit, OBJECT_TYPE objType);
void ExecuteMapMemory(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteUnmapMemory(size_t lineNumber, const CsvSplit& csvSplit);
@ -1158,10 +1164,14 @@ void Player::ExecuteLine(size_t lineNumber, const StrRange& line)
ExecuteDestroyImage(lineNumber, csvSplit);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::FreeMemory]))
ExecuteFreeMemory(lineNumber, csvSplit);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::FreeMemoryPages]))
ExecuteFreeMemoryPages(lineNumber, csvSplit);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::CreateLostAllocation]))
ExecuteCreateLostAllocation(lineNumber, csvSplit);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::AllocateMemory]))
ExecuteAllocateMemory(lineNumber, csvSplit);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::AllocateMemoryPages]))
ExecuteAllocateMemoryPages(lineNumber, csvSplit);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::AllocateMemoryForBuffer]))
ExecuteAllocateMemoryForBufferOrImage(lineNumber, csvSplit, OBJECT_TYPE::BUFFER);
else if(StrRangeEq(functionName, VMA_FUNCTION_NAMES[(uint32_t)VMA_FUNCTION::AllocateMemoryForImage]))
@ -2400,6 +2410,53 @@ void Player::ExecuteCreateImage(size_t lineNumber, const CsvSplit& csvSplit)
}
}
void Player::ExecuteFreeMemoryPages(size_t lineNumber, const CsvSplit& csvSplit)
{
m_Stats.RegisterFunctionCall(VMA_FUNCTION::FreeMemoryPages);
if(ValidateFunctionParameterCount(lineNumber, csvSplit, 1, false))
{
std::vector<uint64_t> origAllocPtrs;
if(StrRangeToPtrList(csvSplit.GetRange(FIRST_PARAM_INDEX), origAllocPtrs))
{
const size_t allocCount = origAllocPtrs.size();
size_t notNullCount = 0;
for(size_t i = 0; i < allocCount; ++i)
{
const uint64_t origAllocPtr = origAllocPtrs[i];
if(origAllocPtr != 0)
{
const auto it = m_Allocations.find(origAllocPtr);
if(it != m_Allocations.end())
{
Destroy(it->second);
m_Allocations.erase(it);
++notNullCount;
}
else
{
if(IssueWarning())
{
printf("Line %zu: Allocation %llX not found.\n", lineNumber, origAllocPtr);
}
}
}
}
if(notNullCount)
{
UpdateMemStats();
}
}
else
{
if(IssueWarning())
{
printf("Line %zu: Invalid parameters for vmaFreeMemoryPages.\n", lineNumber);
}
}
}
}
void Player::ExecuteCreateLostAllocation(size_t lineNumber, const CsvSplit& csvSplit)
{
m_Stats.RegisterFunctionCall(VMA_FUNCTION::CreateLostAllocation);
@ -2479,6 +2536,68 @@ void Player::ExecuteAllocateMemory(size_t lineNumber, const CsvSplit& csvSplit)
}
}
void Player::ExecuteAllocateMemoryPages(size_t lineNumber, const CsvSplit& csvSplit)
{
m_Stats.RegisterFunctionCall(VMA_FUNCTION::AllocateMemoryPages);
if(ValidateFunctionParameterCount(lineNumber, csvSplit, 11, true))
{
VkMemoryRequirements memReq = {};
VmaAllocationCreateInfo allocCreateInfo = {};
uint64_t origPool = 0;
std::vector<uint64_t> origPtrs;
if(StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX), memReq.size) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 1), memReq.alignment) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 2), memReq.memoryTypeBits) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 3), allocCreateInfo.flags) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 4), (uint32_t&)allocCreateInfo.usage) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 5), allocCreateInfo.requiredFlags) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 6), allocCreateInfo.preferredFlags) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 7), allocCreateInfo.memoryTypeBits) &&
StrRangeToPtr(csvSplit.GetRange(FIRST_PARAM_INDEX + 8), origPool) &&
StrRangeToPtrList(csvSplit.GetRange(FIRST_PARAM_INDEX + 9), origPtrs))
{
const size_t allocCount = origPtrs.size();
if(allocCount > 0)
{
FindPool(lineNumber, origPool, allocCreateInfo.pool);
if(csvSplit.GetCount() > FIRST_PARAM_INDEX + 10)
{
PrepareUserData(
lineNumber,
allocCreateInfo.flags,
csvSplit.GetRange(FIRST_PARAM_INDEX + 10),
csvSplit.GetLine(),
allocCreateInfo.pUserData);
}
UpdateMemStats();
m_Stats.RegisterCreateAllocation(allocCount);
std::vector<VmaAllocation> allocations(allocCount);
VkResult res = vmaAllocateMemoryPages(m_Allocator, &memReq, &allocCreateInfo, allocCount, allocations.data(), nullptr);
for(size_t i = 0; i < allocCount; ++i)
{
Allocation allocDesc = {};
allocDesc.allocationFlags = allocCreateInfo.flags;
allocDesc.allocation = allocations[i];
AddAllocation(lineNumber, origPtrs[i], res, "vmaAllocateMemoryPages", std::move(allocDesc));
}
}
}
else
{
if(IssueWarning())
{
printf("Line %zu: Invalid parameters for vmaAllocateMemoryPages.\n", lineNumber);
}
}
}
}
void Player::ExecuteAllocateMemoryForBufferOrImage(size_t lineNumber, const CsvSplit& csvSplit, OBJECT_TYPE objType)
{
switch(objType)

View File

@ -22,6 +22,7 @@
#ifdef _WIN32
#include "SparseBindingTest.h"
#include "Tests.h"
#include "VmaUsage.h"
#include "Common.h"
@ -46,6 +47,7 @@ bool g_MemoryAliasingWarningEnabled = true;
static bool g_EnableValidationLayer = true;
static bool VK_KHR_get_memory_requirements2_enabled = false;
static bool VK_KHR_dedicated_allocation_enabled = false;
bool g_SparseBindingEnabled = false;
static HINSTANCE g_hAppInstance;
static HWND g_hWnd;
@ -62,11 +64,13 @@ static std::vector<VkFramebuffer> g_Framebuffers;
static VkCommandPool g_hCommandPool;
static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
VkFence g_ImmediateFence;
static uint32_t g_NextCommandBufferIndex;
static VkSemaphore g_hImageAvailableSemaphore;
static VkSemaphore g_hRenderFinishedSemaphore;
static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
static VkDescriptorSetLayout g_hDescriptorSetLayout;
static VkDescriptorPool g_hDescriptorPool;
static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
@ -86,6 +90,7 @@ static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
static VkDebugReportCallbackEXT g_hCallback;
static VkQueue g_hGraphicsQueue;
VkQueue g_hSparseBindingQueue;
VkCommandBuffer g_hTemporaryCommandBuffer;
static VkPipelineLayout g_hPipelineLayout;
@ -144,7 +149,7 @@ void EndSingleTimeCommands()
ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
}
static void LoadShader(std::vector<char>& out, const char* fileName)
void LoadShader(std::vector<char>& out, const char* fileName)
{
std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
if(file.is_open() == false)
@ -1196,8 +1201,10 @@ static void InitializeApplication()
VkPhysicalDeviceProperties physicalDeviceProperties = {};
vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
//VkPhysicalDeviceFeatures physicalDeviceFreatures = {};
//vkGetPhysicalDeviceFeatures(g_PhysicalDevice, &physicalDeviceFreatures);
VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
// Find queue family index
@ -1208,13 +1215,16 @@ static void InitializeApplication()
vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
for(uint32_t i = 0;
(i < queueFamilyCount) &&
(g_GraphicsQueueFamilyIndex == UINT_MAX || g_PresentQueueFamilyIndex == UINT_MAX);
(g_GraphicsQueueFamilyIndex == UINT_MAX ||
g_PresentQueueFamilyIndex == UINT_MAX ||
(g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
++i)
{
if(queueFamilies[i].queueCount > 0)
{
const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
if((g_GraphicsQueueFamilyIndex != 0) &&
((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0))
((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
{
g_GraphicsQueueFamilyIndex = i;
}
@ -1225,26 +1235,56 @@ static void InitializeApplication()
{
g_PresentQueueFamilyIndex = i;
}
if(g_SparseBindingEnabled &&
g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
(queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
{
g_SparseBindingQueueFamilyIndex = i;
}
}
}
assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
// Create logical device
const float queuePriority = 1.f;
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
deviceQueueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
deviceQueueCreateInfo[0].queueCount = 1;
deviceQueueCreateInfo[0].pQueuePriorities = &queuePriority;
deviceQueueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
deviceQueueCreateInfo[1].queueFamilyIndex = g_PresentQueueFamilyIndex;
deviceQueueCreateInfo[1].queueCount = 1;
deviceQueueCreateInfo[1].pQueuePriorities = &queuePriority;
VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
uint32_t queueCount = 1;
queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
queueCreateInfo[0].queueCount = 1;
queueCreateInfo[0].pQueuePriorities = &queuePriority;
if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
{
queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
queueCreateInfo[queueCount].queueCount = 1;
queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
++queueCount;
}
if(g_SparseBindingEnabled &&
g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
{
queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
queueCreateInfo[queueCount].queueCount = 1;
queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
++queueCount;
}
VkPhysicalDeviceFeatures deviceFeatures = {};
deviceFeatures.fillModeNonSolid = VK_TRUE;
//deviceFeatures.fillModeNonSolid = VK_TRUE;
deviceFeatures.samplerAnisotropy = VK_TRUE;
deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
// Determine list of device extensions to enable.
std::vector<const char*> enabledDeviceExtensions;
@ -1279,8 +1319,8 @@ static void InitializeApplication()
deviceCreateInfo.ppEnabledLayerNames = nullptr;
deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
deviceCreateInfo.queueCreateInfoCount = g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex ? 2 : 1;
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
deviceCreateInfo.queueCreateInfoCount = queueCount;
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, nullptr, &g_hDevice) );
@ -1317,13 +1357,19 @@ static void InitializeApplication()
ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
// Retrieve queue (doesn't need to be destroyed)
// Retrieve queues (don't need to be destroyed).
vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
assert(g_hGraphicsQueue);
assert(g_hPresentQueue);
if(g_SparseBindingEnabled)
{
vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
assert(g_hSparseBindingQueue);
}
// Create command pool
VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
@ -1344,6 +1390,8 @@ static void InitializeApplication()
ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_MainCommandBufferExecutedFances[i]) );
}
ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_ImmediateFence) );
commandBufferInfo.commandBufferCount = 1;
ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
@ -1469,6 +1517,12 @@ static void FinalizeApplication()
g_hSampler = VK_NULL_HANDLE;
}
if(g_ImmediateFence)
{
vkDestroyFence(g_hDevice, g_ImmediateFence, nullptr);
g_ImmediateFence = VK_NULL_HANDLE;
}
for(size_t i = COMMAND_BUFFER_COUNT; i--; )
{
if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
@ -1732,6 +1786,23 @@ static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
printf("ERROR: %s\n", ex.what());
}
break;
case 'S':
try
{
if(g_SparseBindingEnabled)
{
TestSparseBinding();
}
else
{
printf("Sparse binding not supported.\n");
}
}
catch(const std::exception& ex)
{
printf("ERROR: %s\n", ex.what());
}
break;
}
return 0;

View File

@ -2484,7 +2484,7 @@ typedef struct VmaAllocationInfo {
@param[out] pAllocation Handle to allocated memory.
@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo().
You should free the memory using vmaFreeMemory().
You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages().
It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(),
vmaCreateBuffer(), vmaCreateImage() instead whenever possible.
@ -2496,6 +2496,33 @@ VkResult vmaAllocateMemory(
VmaAllocation* pAllocation,
VmaAllocationInfo* pAllocationInfo);
/** \brief General purpose memory allocation for multiple allocation objects at once.
@param allocator Allocator object.
@param pVkMemoryRequirements Memory requirements for each allocation.
@param pCreateInfo Creation parameters for each alloction.
@param allocationCount Number of allocations to make.
@param[out] pAllocations Pointer to array that will be filled with handles to created allocations.
@param[out] pAlocationInfo Optional. Pointer to array that will be filled with parameters of created allocations.
You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages().
Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding.
It is just a general purpose allocation function able to make multiple allocations at once.
It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times.
All allocations are made using same parameters. All of them are created out of the same memory pool and type.
If any allocation fails, all allocations already made within this function call are also freed, so that when
returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`.
*/
VkResult vmaAllocateMemoryPages(
VmaAllocator allocator,
const VkMemoryRequirements* pVkMemoryRequirements,
const VmaAllocationCreateInfo* pCreateInfo,
size_t allocationCount,
VmaAllocation* pAllocations,
VmaAllocationInfo* pAllocationInfo);
/**
@param[out] pAllocation Handle to allocated memory.
@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo().
@ -2517,11 +2544,29 @@ VkResult vmaAllocateMemoryForImage(
VmaAllocation* pAllocation,
VmaAllocationInfo* pAllocationInfo);
/// Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage().
/** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage().
Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped.
*/
void vmaFreeMemory(
VmaAllocator allocator,
VmaAllocation allocation);
/** \brief Frees memory and destroys multiple allocations.
Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding.
It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(),
vmaAllocateMemoryPages() and other functions.
It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times.
Allocations in `pAllocations` array can come from any memory pools and types.
Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped.
*/
void vmaFreeMemoryPages(
VmaAllocator allocator,
size_t allocationCount,
VmaAllocation* pAllocations);
/** \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.
@ -5764,7 +5809,8 @@ public:
VkDeviceSize alignment,
const VmaAllocationCreateInfo& createInfo,
VmaSuballocationType suballocType,
VmaAllocation* pAllocation);
size_t allocationCount,
VmaAllocation* pAllocations);
void Free(
VmaAllocation hAllocation);
@ -5831,6 +5877,15 @@ private:
// after this call.
void IncrementallySortBlocks();
VkResult AllocatePage(
VmaPool hCurrentPool,
uint32_t currentFrameIndex,
VkDeviceSize size,
VkDeviceSize alignment,
const VmaAllocationCreateInfo& createInfo,
VmaSuballocationType suballocType,
VmaAllocation* pAllocation);
// To be used only without CAN_MAKE_OTHER_LOST flag.
VkResult AllocateFromBlock(
VmaDeviceMemoryBlock* pBlock,
@ -6347,6 +6402,11 @@ public:
const VkMemoryRequirements& vkMemReq,
const VmaAllocationCreateInfo& createInfo,
VmaAllocation allocation);
void RecordAllocateMemoryPages(uint32_t frameIndex,
const VkMemoryRequirements& vkMemReq,
const VmaAllocationCreateInfo& createInfo,
uint64_t allocationCount,
const VmaAllocation* pAllocations);
void RecordAllocateMemoryForBuffer(uint32_t frameIndex,
const VkMemoryRequirements& vkMemReq,
bool requiresDedicatedAllocation,
@ -6361,6 +6421,9 @@ public:
VmaAllocation allocation);
void RecordFreeMemory(uint32_t frameIndex,
VmaAllocation allocation);
void RecordFreeMemoryPages(uint32_t frameIndex,
uint64_t allocationCount,
const VmaAllocation* pAllocations);
void RecordResizeAllocation(
uint32_t frameIndex,
VmaAllocation allocation,
@ -6443,6 +6506,7 @@ private:
}
}
void PrintPointerList(uint64_t count, const VmaAllocation* pItems);
void Flush();
};
@ -6546,10 +6610,13 @@ public:
VkImage dedicatedImage,
const VmaAllocationCreateInfo& createInfo,
VmaSuballocationType suballocType,
VmaAllocation* pAllocation);
size_t allocationCount,
VmaAllocation* pAllocations);
// Main deallocation function.
void FreeMemory(const VmaAllocation allocation);
void FreeMemory(
size_t allocationCount,
const VmaAllocation* pAllocations);
VkResult ResizeAllocation(
const VmaAllocation alloc,
@ -6632,9 +6699,21 @@ private:
const VmaAllocationCreateInfo& createInfo,
uint32_t memTypeIndex,
VmaSuballocationType suballocType,
size_t allocationCount,
VmaAllocation* pAllocations);
// Helper function only to be used inside AllocateDedicatedMemory.
VkResult AllocateDedicatedMemoryPage(
VkDeviceSize size,
VmaSuballocationType suballocType,
uint32_t memTypeIndex,
const VkMemoryAllocateInfo& allocInfo,
bool map,
bool isUserDataString,
void* pUserData,
VmaAllocation* pAllocation);
// Allocates and registers new VkDeviceMemory specifically for single allocation.
// Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
VkResult AllocateDedicatedMemory(
VkDeviceSize size,
VmaSuballocationType suballocType,
@ -6644,7 +6723,8 @@ private:
void* pUserData,
VkBuffer dedicatedBuffer,
VkImage dedicatedImage,
VmaAllocation* pAllocation);
size_t allocationCount,
VmaAllocation* pAllocations);
// Tries to free pMemory as Dedicated Memory. Returns true if found and freed.
void FreeDedicatedMemory(VmaAllocation allocation);
@ -11225,6 +11305,51 @@ bool VmaBlockVector::IsCorruptionDetectionEnabled() const
static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
VkResult VmaBlockVector::Allocate(
VmaPool hCurrentPool,
uint32_t currentFrameIndex,
VkDeviceSize size,
VkDeviceSize alignment,
const VmaAllocationCreateInfo& createInfo,
VmaSuballocationType suballocType,
size_t allocationCount,
VmaAllocation* pAllocations)
{
size_t allocIndex;
VkResult res = VK_SUCCESS;
{
VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
{
res = AllocatePage(
hCurrentPool,
currentFrameIndex,
size,
alignment,
createInfo,
suballocType,
pAllocations + allocIndex);
if(res != VK_SUCCESS)
{
break;
}
}
}
if(res != VK_SUCCESS)
{
// Free all already created allocations.
while(allocIndex--)
{
Free(pAllocations[allocIndex]);
}
memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
}
return res;
}
VkResult VmaBlockVector::AllocatePage(
VmaPool hCurrentPool,
uint32_t currentFrameIndex,
VkDeviceSize size,
@ -11276,8 +11401,6 @@ VkResult VmaBlockVector::Allocate(
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
/*
Under certain condition, this whole section can be skipped for optimization, so
we move on directly to trying to allocate with canMakeOtherLost. That's the case
@ -13371,6 +13494,32 @@ void VmaRecorder::RecordAllocateMemory(uint32_t frameIndex,
Flush();
}
void VmaRecorder::RecordAllocateMemoryPages(uint32_t frameIndex,
const VkMemoryRequirements& vkMemReq,
const VmaAllocationCreateInfo& createInfo,
uint64_t allocationCount,
const VmaAllocation* pAllocations)
{
CallParams callParams;
GetBasicParams(callParams);
VmaMutexLock lock(m_FileMutex, m_UseMutex);
UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryPages,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,", callParams.threadId, callParams.time, frameIndex,
vkMemReq.size,
vkMemReq.alignment,
vkMemReq.memoryTypeBits,
createInfo.flags,
createInfo.usage,
createInfo.requiredFlags,
createInfo.preferredFlags,
createInfo.memoryTypeBits,
createInfo.pool);
PrintPointerList(allocationCount, pAllocations);
fprintf(m_File, ",%s\n", userDataStr.GetString());
Flush();
}
void VmaRecorder::RecordAllocateMemoryForBuffer(uint32_t frameIndex,
const VkMemoryRequirements& vkMemReq,
bool requiresDedicatedAllocation,
@ -13441,6 +13590,20 @@ void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
Flush();
}
void VmaRecorder::RecordFreeMemoryPages(uint32_t frameIndex,
uint64_t allocationCount,
const VmaAllocation* pAllocations)
{
CallParams callParams;
GetBasicParams(callParams);
VmaMutexLock lock(m_FileMutex, m_UseMutex);
fprintf(m_File, "%u,%.3f,%u,vmaFreeMemoryPages,", callParams.threadId, callParams.time, frameIndex);
PrintPointerList(allocationCount, pAllocations);
fprintf(m_File, "\n");
Flush();
}
void VmaRecorder::RecordResizeAllocation(
uint32_t frameIndex,
VmaAllocation allocation,
@ -13767,6 +13930,18 @@ void VmaRecorder::GetBasicParams(CallParams& outParams)
outParams.time = (double)(counter.QuadPart - m_StartCounter) / (double)m_Freq;
}
void VmaRecorder::PrintPointerList(uint64_t count, const VmaAllocation* pItems)
{
if(count)
{
fprintf(m_File, "%p", pItems[0]);
for(uint64_t i = 1; i < count; ++i)
{
fprintf(m_File, " %p", pItems[i]);
}
}
}
void VmaRecorder::Flush()
{
if((m_Flags & VMA_RECORD_FLUSH_AFTER_CALL_BIT) != 0)
@ -14033,10 +14208,11 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
const VmaAllocationCreateInfo& createInfo,
uint32_t memTypeIndex,
VmaSuballocationType suballocType,
VmaAllocation* pAllocation)
size_t allocationCount,
VmaAllocation* pAllocations)
{
VMA_ASSERT(pAllocation != VMA_NULL);
VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, Size=%llu", memTypeIndex, vkMemReq.size);
VMA_ASSERT(pAllocations != VMA_NULL);
VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, vkMemReq.size);
VmaAllocationCreateInfo finalCreateInfo = createInfo;
@ -14081,7 +14257,8 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
finalCreateInfo.pUserData,
dedicatedBuffer,
dedicatedImage,
pAllocation);
allocationCount,
pAllocations);
}
}
else
@ -14093,7 +14270,8 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
alignment,
finalCreateInfo,
suballocType,
pAllocation);
allocationCount,
pAllocations);
if(res == VK_SUCCESS)
{
return res;
@ -14115,7 +14293,8 @@ VkResult VmaAllocator_T::AllocateMemoryOfType(
finalCreateInfo.pUserData,
dedicatedBuffer,
dedicatedImage,
pAllocation);
allocationCount,
pAllocations);
if(res == VK_SUCCESS)
{
// Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
@ -14141,9 +14320,10 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
void* pUserData,
VkBuffer dedicatedBuffer,
VkImage dedicatedImage,
VmaAllocation* pAllocation)
size_t allocationCount,
VmaAllocation* pAllocations)
{
VMA_ASSERT(pAllocation);
VMA_ASSERT(allocationCount > 0 && pAllocations);
VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
allocInfo.memoryTypeIndex = memTypeIndex;
@ -14167,7 +14347,80 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
}
#endif // #if VMA_DEDICATED_ALLOCATION
// Allocate VkDeviceMemory.
size_t allocIndex;
VkResult res;
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
{
res = AllocateDedicatedMemoryPage(
size,
suballocType,
memTypeIndex,
allocInfo,
map,
isUserDataString,
pUserData,
pAllocations + allocIndex);
if(res != VK_SUCCESS)
{
break;
}
}
if(res == VK_SUCCESS)
{
// Register them in m_pDedicatedAllocations.
{
VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
VMA_ASSERT(pDedicatedAllocations);
for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
{
VmaVectorInsertSorted<VmaPointerLess>(*pDedicatedAllocations, pAllocations[allocIndex]);
}
}
VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
}
else
{
// Free all already created allocations.
while(allocIndex--)
{
VmaAllocation currAlloc = pAllocations[allocIndex];
VkDeviceMemory hMemory = currAlloc->GetMemory();
/*
There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
before vkFreeMemory.
if(currAlloc->GetMappedData() != VMA_NULL)
{
(*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
}
*/
FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
currAlloc->SetUserData(this, VMA_NULL);
vma_delete(this, currAlloc);
}
memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
}
return res;
}
VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
VkDeviceSize size,
VmaSuballocationType suballocType,
uint32_t memTypeIndex,
const VkMemoryAllocateInfo& allocInfo,
bool map,
bool isUserDataString,
void* pUserData,
VmaAllocation* pAllocation)
{
VkDeviceMemory hMemory = VK_NULL_HANDLE;
VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
if(res < 0)
@ -14202,16 +14455,6 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory(
FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
}
// Register it in m_pDedicatedAllocations.
{
VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
VMA_ASSERT(pDedicatedAllocations);
VmaVectorInsertSorted<VmaPointerLess>(*pDedicatedAllocations, *pAllocation);
}
VMA_DEBUG_LOG(" Allocated DedicatedMemory MemoryTypeIndex=#%u", memTypeIndex);
return VK_SUCCESS;
}
@ -14287,8 +14530,11 @@ VkResult VmaAllocator_T::AllocateMemory(
VkImage dedicatedImage,
const VmaAllocationCreateInfo& createInfo,
VmaSuballocationType suballocType,
VmaAllocation* pAllocation)
size_t allocationCount,
VmaAllocation* pAllocations)
{
memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
VMA_ASSERT(VmaIsPow2(vkMemReq.alignment));
if(vkMemReq.size == 0)
@ -14339,7 +14585,8 @@ VkResult VmaAllocator_T::AllocateMemory(
alignmentForPool,
createInfo,
suballocType,
pAllocation);
allocationCount,
pAllocations);
}
else
{
@ -14362,7 +14609,8 @@ VkResult VmaAllocator_T::AllocateMemory(
createInfo,
memTypeIndex,
suballocType,
pAllocation);
allocationCount,
pAllocations);
// Succeeded on first try.
if(res == VK_SUCCESS)
{
@ -14392,7 +14640,8 @@ VkResult VmaAllocator_T::AllocateMemory(
createInfo,
memTypeIndex,
suballocType,
pAllocation);
allocationCount,
pAllocations);
// Allocation from this alternative memory type succeeded.
if(res == VK_SUCCESS)
{
@ -14415,10 +14664,18 @@ VkResult VmaAllocator_T::AllocateMemory(
}
}
void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
void VmaAllocator_T::FreeMemory(
size_t allocationCount,
const VmaAllocation* pAllocations)
{
VMA_ASSERT(allocation);
VMA_ASSERT(pAllocations);
for(size_t allocIndex = allocationCount; allocIndex--; )
{
VmaAllocation allocation = pAllocations[allocIndex];
if(allocation != VK_NULL_HANDLE)
{
if(TouchAllocation(allocation))
{
if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
@ -14455,6 +14712,8 @@ void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
allocation->SetUserData(this, VMA_NULL);
vma_delete(this, allocation);
}
}
}
VkResult VmaAllocator_T::ResizeAllocation(
const VmaAllocation alloc,
@ -15660,6 +15919,7 @@ VkResult vmaAllocateMemory(
VK_NULL_HANDLE, // dedicatedImage
*pCreateInfo,
VMA_SUBALLOCATION_TYPE_UNKNOWN,
1, // allocationCount
pAllocation);
#if VMA_RECORDING_ENABLED
@ -15681,6 +15941,59 @@ VkResult vmaAllocateMemory(
return result;
}
VkResult vmaAllocateMemoryPages(
VmaAllocator allocator,
const VkMemoryRequirements* pVkMemoryRequirements,
const VmaAllocationCreateInfo* pCreateInfo,
size_t allocationCount,
VmaAllocation* pAllocations,
VmaAllocationInfo* pAllocationInfo)
{
if(allocationCount == 0)
{
return VK_SUCCESS;
}
VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations);
VMA_DEBUG_LOG("vmaAllocateMemoryPages");
VMA_DEBUG_GLOBAL_MUTEX_LOCK
VkResult result = allocator->AllocateMemory(
*pVkMemoryRequirements,
false, // requiresDedicatedAllocation
false, // prefersDedicatedAllocation
VK_NULL_HANDLE, // dedicatedBuffer
VK_NULL_HANDLE, // dedicatedImage
*pCreateInfo,
VMA_SUBALLOCATION_TYPE_UNKNOWN,
allocationCount,
pAllocations);
#if VMA_RECORDING_ENABLED
if(allocator->GetRecorder() != VMA_NULL)
{
allocator->GetRecorder()->RecordAllocateMemoryPages(
allocator->GetCurrentFrameIndex(),
*pVkMemoryRequirements,
*pCreateInfo,
(uint64_t)allocationCount,
pAllocations);
}
#endif
if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
{
for(size_t i = 0; i < allocationCount; ++i)
{
allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i);
}
}
return result;
}
VkResult vmaAllocateMemoryForBuffer(
VmaAllocator allocator,
VkBuffer buffer,
@ -15709,6 +16022,7 @@ VkResult vmaAllocateMemoryForBuffer(
VK_NULL_HANDLE, // dedicatedImage
*pCreateInfo,
VMA_SUBALLOCATION_TYPE_BUFFER,
1, // allocationCount
pAllocation);
#if VMA_RECORDING_ENABLED
@ -15759,6 +16073,7 @@ VkResult vmaAllocateMemoryForImage(
image, // dedicatedImage
*pCreateInfo,
VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
1, // allocationCount
pAllocation);
#if VMA_RECORDING_ENABLED
@ -15806,7 +16121,38 @@ void vmaFreeMemory(
}
#endif
allocator->FreeMemory(allocation);
allocator->FreeMemory(
1, // allocationCount
&allocation);
}
void vmaFreeMemoryPages(
VmaAllocator allocator,
size_t allocationCount,
VmaAllocation* pAllocations)
{
if(allocationCount == 0)
{
return;
}
VMA_ASSERT(allocator);
VMA_DEBUG_LOG("vmaFreeMemoryPages");
VMA_DEBUG_GLOBAL_MUTEX_LOCK
#if VMA_RECORDING_ENABLED
if(allocator->GetRecorder() != VMA_NULL)
{
allocator->GetRecorder()->RecordFreeMemoryPages(
allocator->GetCurrentFrameIndex(),
(uint64_t)allocationCount,
pAllocations);
}
#endif
allocator->FreeMemory(allocationCount, pAllocations);
}
VkResult vmaResizeAllocation(
@ -16201,6 +16547,7 @@ VkResult vmaCreateBuffer(
VK_NULL_HANDLE, // dedicatedImage
*pAllocationCreateInfo,
VMA_SUBALLOCATION_TYPE_BUFFER,
1, // allocationCount
pAllocation);
#if VMA_RECORDING_ENABLED
@ -16231,7 +16578,9 @@ VkResult vmaCreateBuffer(
return VK_SUCCESS;
}
allocator->FreeMemory(*pAllocation);
allocator->FreeMemory(
1, // allocationCount
pAllocation);
*pAllocation = VK_NULL_HANDLE;
(*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
*pBuffer = VK_NULL_HANDLE;
@ -16276,7 +16625,9 @@ void vmaDestroyBuffer(
if(allocation != VK_NULL_HANDLE)
{
allocator->FreeMemory(allocation);
allocator->FreeMemory(
1, // allocationCount
&allocation);
}
}
@ -16333,6 +16684,7 @@ VkResult vmaCreateImage(
*pImage, // dedicatedImage
*pAllocationCreateInfo,
suballocType,
1, // allocationCount
pAllocation);
#if VMA_RECORDING_ENABLED
@ -16363,7 +16715,9 @@ VkResult vmaCreateImage(
return VK_SUCCESS;
}
allocator->FreeMemory(*pAllocation);
allocator->FreeMemory(
1, // allocationCount
pAllocation);
*pAllocation = VK_NULL_HANDLE;
(*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
*pImage = VK_NULL_HANDLE;
@ -16407,7 +16761,9 @@ void vmaDestroyImage(
}
if(allocation != VK_NULL_HANDLE)
{
allocator->FreeMemory(allocation);
allocator->FreeMemory(
1, // allocationCount
&allocation);
}
}