mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2024-11-27 00:44:35 +00:00
170 lines
19 KiB
HTML
170 lines
19 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
<meta name="generator" content="Doxygen 1.8.14"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<title>Vulkan Memory Allocator: Custom memory pools</title>
|
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
<script type="text/javascript" src="dynsections.js"></script>
|
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="search/searchdata.js"></script>
|
|
<script type="text/javascript" src="search/search.js"></script>
|
|
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
|
</head>
|
|
<body>
|
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
<div id="titlearea">
|
|
<table cellspacing="0" cellpadding="0">
|
|
<tbody>
|
|
<tr style="height: 56px;">
|
|
<td id="projectalign" style="padding-left: 0.5em;">
|
|
<div id="projectname">Vulkan Memory Allocator
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!-- end header part -->
|
|
<!-- Generated by Doxygen 1.8.14 -->
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
|
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|
/* @license-end */
|
|
</script>
|
|
<script type="text/javascript" src="menudata.js"></script>
|
|
<script type="text/javascript" src="menu.js"></script>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
|
$(function() {
|
|
initMenu('',true,false,'search.php','Search');
|
|
$(document).ready(function() { init_search(); });
|
|
});
|
|
/* @license-end */</script>
|
|
<div id="main-nav"></div>
|
|
<!-- window showing the filter options -->
|
|
<div id="MSearchSelectWindow"
|
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
|
</div>
|
|
|
|
<!-- iframe showing the search results (closed by default) -->
|
|
<div id="MSearchResultsWindow">
|
|
<iframe src="javascript:void(0)" frameborder="0"
|
|
name="MSearchResults" id="MSearchResults">
|
|
</iframe>
|
|
</div>
|
|
|
|
<div id="nav-path" class="navpath">
|
|
<ul>
|
|
<li class="navelem"><a class="el" href="index.html">Vulkan Memory Allocator</a></li> </ul>
|
|
</div>
|
|
</div><!-- top -->
|
|
<div class="header">
|
|
<div class="headertitle">
|
|
<div class="title">Custom memory pools </div> </div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="textblock"><p>A memory pool contains a number of <code>VkDeviceMemory</code> blocks. The library automatically creates and manages default pool for each memory type available on the device. Default memory pool automatically grows in size. Size of allocated blocks is also variable and managed automatically.</p>
|
|
<p>You can create custom pool and allocate memory out of it. It can be useful if you want to:</p>
|
|
<ul>
|
|
<li>Keep certain kind of allocations separate from others.</li>
|
|
<li>Enforce particular, fixed size of Vulkan memory blocks.</li>
|
|
<li>Limit maximum amount of Vulkan memory allocated for that pool.</li>
|
|
<li>Reserve minimum or fixed amount of Vulkan memory always preallocated for that pool.</li>
|
|
</ul>
|
|
<p>To use custom memory pools:</p>
|
|
<ol type="1">
|
|
<li>Fill <a class="el" href="struct_vma_pool_create_info.html" title="Describes parameter of created VmaPool. ">VmaPoolCreateInfo</a> structure.</li>
|
|
<li>Call <a class="el" href="vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50" title="Allocates Vulkan device memory and creates VmaPool object. ">vmaCreatePool()</a> to obtain <a class="el" href="struct_vma_pool.html" title="Represents custom memory pool. ">VmaPool</a> handle.</li>
|
|
<li>When making an allocation, set <a class="el" href="struct_vma_allocation_create_info.html#a6272c0555cfd1fe28bff1afeb6190150" title="Pool that this allocation should be created in. ">VmaAllocationCreateInfo::pool</a> to this handle. You don't need to specify any other parameters of this structure, like <code>usage</code>.</li>
|
|
</ol>
|
|
<p>Example:</p>
|
|
<div class="fragment"><div class="line"><span class="comment">// Create a pool that can have at most 2 blocks, 128 MiB each.</span></div><div class="line"><a class="code" href="struct_vma_pool_create_info.html">VmaPoolCreateInfo</a> poolCreateInfo = {};</div><div class="line">poolCreateInfo.<a class="code" href="struct_vma_pool_create_info.html#a596fa76b685d3f1f688f84a709a5b319">memoryTypeIndex</a> = ...</div><div class="line">poolCreateInfo.blockSize = 128ull * 1024 * 1024;</div><div class="line">poolCreateInfo.<a class="code" href="struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c">maxBlockCount</a> = 2;</div><div class="line"></div><div class="line"><a class="code" href="struct_vma_pool.html">VmaPool</a> pool;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50">vmaCreatePool</a>(allocator, &poolCreateInfo, &pool);</div><div class="line"></div><div class="line"><span class="comment">// Allocate a buffer out of it.</span></div><div class="line">VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };</div><div class="line">bufCreateInfo.size = 1024;</div><div class="line">bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;</div><div class="line"></div><div class="line"><a class="code" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> allocCreateInfo = {};</div><div class="line">allocCreateInfo.<a class="code" href="struct_vma_allocation_create_info.html#a6272c0555cfd1fe28bff1afeb6190150">pool</a> = pool;</div><div class="line"></div><div class="line">VkBuffer buf;</div><div class="line"><a class="code" href="struct_vma_allocation.html">VmaAllocation</a> alloc;</div><div class="line"><a class="code" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> allocInfo;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer</a>(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);</div></div><!-- fragment --><p>You have to free all allocations made from this pool before destroying it.</p>
|
|
<div class="fragment"><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77">vmaDestroyBuffer</a>(allocator, buf, alloc);</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1">vmaDestroyPool</a>(allocator, pool);</div></div><!-- fragment --><h1><a class="anchor" id="custom_memory_pools_MemTypeIndex"></a>
|
|
Choosing memory type index</h1>
|
|
<p>When creating a pool, you must explicitly specify memory type index. To find the one suitable for your buffers or images, you can use helper functions <a class="el" href="vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888" title="Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. ">vmaFindMemoryTypeIndexForBufferInfo()</a>, <a class="el" href="vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472" title="Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. ">vmaFindMemoryTypeIndexForImageInfo()</a>. You need to provide structures with example parameters of buffers or images that you are going to create in that pool.</p>
|
|
<div class="fragment"><div class="line">VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };</div><div class="line">exampleBufCreateInfo.size = 1024; <span class="comment">// Whatever.</span></div><div class="line">exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; <span class="comment">// Change if needed.</span></div><div class="line"></div><div class="line"><a class="code" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> allocCreateInfo = {};</div><div class="line">allocCreateInfo.<a class="code" href="struct_vma_allocation_create_info.html#accb8b06b1f677d858cb9af20705fa910">usage</a> = <a class="code" href="vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7">VMA_MEMORY_USAGE_GPU_ONLY</a>; <span class="comment">// Change if needed.</span></div><div class="line"></div><div class="line">uint32_t memTypeIndex;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888">vmaFindMemoryTypeIndexForBufferInfo</a>(allocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex);</div><div class="line"></div><div class="line"><a class="code" href="struct_vma_pool_create_info.html">VmaPoolCreateInfo</a> poolCreateInfo = {};</div><div class="line">poolCreateInfo.<a class="code" href="struct_vma_pool_create_info.html#a596fa76b685d3f1f688f84a709a5b319">memoryTypeIndex</a> = memTypeIndex;</div><div class="line"><span class="comment">// ...</span></div></div><!-- fragment --><p>When creating buffers/images allocated in that pool, provide following parameters:</p>
|
|
<ul>
|
|
<li><code>VkBufferCreateInfo</code>: Prefer to pass same parameters as above. Otherwise you risk creating resources in a memory type that is not suitable for them, which may result in undefined behavior. Using different <code>VK_BUFFER_USAGE_</code> flags may work, but you shouldn't create images in a pool intended for buffers or the other way around.</li>
|
|
<li><a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a>: You don't need to pass same parameters. Fill only <code>pool</code> member. Other members are ignored anyway.</li>
|
|
</ul>
|
|
<h1><a class="anchor" id="linear_algorithm"></a>
|
|
Linear allocation algorithm</h1>
|
|
<p>Each Vulkan memory block managed by this library has accompanying metadata that keeps track of used and unused regions. By default, the metadata structure and algorithm tries to find best place for new allocations among free regions to optimize memory usage. This way you can allocate and free objects in any order.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_1_algo_default.png" alt="Default allocation algorithm"/>
|
|
</div>
|
|
<p>Sometimes there is a need to use simpler, linear allocation algorithm. You can create custom pool that uses such algorithm by adding flag <a class="el" href="vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a13c8a444197c67866be9cb05599fc726" title="Enables alternative, linear allocation algorithm in this pool. ">VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT</a> to <a class="el" href="struct_vma_pool_create_info.html#a8405139f63d078340ae74513a59f5446" title="Use combination of VmaPoolCreateFlagBits. ">VmaPoolCreateInfo::flags</a> while creating <a class="el" href="struct_vma_pool.html" title="Represents custom memory pool. ">VmaPool</a> object. Then an alternative metadata management is used. It always creates new allocations after last one and doesn't reuse free regions after allocations freed in the middle. It results in better allocation performance and less memory consumed by metadata.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_2_algo_linear.png" alt="Linear allocation algorithm"/>
|
|
</div>
|
|
<p>With this one flag, you can create a custom pool that can be used in many ways: free-at-once, stack, double stack, and ring buffer. See below for details.</p>
|
|
<h2><a class="anchor" id="linear_algorithm_free_at_once"></a>
|
|
Free-at-once</h2>
|
|
<p>In a pool that uses linear algorithm, you still need to free all the allocations individually, e.g. by 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#a0d9f4e4ba5bf9aab1f1c746387753d77" title="Destroys Vulkan buffer and frees allocated memory. ">vmaDestroyBuffer()</a>. You can free them in any order. New allocations are always made after last one - free space in the middle is not reused. However, when you release all the allocation and the pool becomes empty, allocation starts from the beginning again. This way you can use linear algorithm to speed up creation of allocations that you are going to release all at once.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_3_free_at_once.png" alt="Free-at-once"/>
|
|
</div>
|
|
<p>This mode is also available for pools created with <a class="el" href="struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c" title="Maximum number of blocks that can be allocated in this pool. Optional. ">VmaPoolCreateInfo::maxBlockCount</a> value that allows multiple memory blocks.</p>
|
|
<h2><a class="anchor" id="linear_algorithm_stack"></a>
|
|
Stack</h2>
|
|
<p>When you free an allocation that was created last, its space can be reused. Thanks to this, if you always release allocations in the order opposite to their creation (LIFO - Last In First Out), you can achieve behavior of a stack.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_4_stack.png" alt="Stack"/>
|
|
</div>
|
|
<p>This mode is also available for pools created with <a class="el" href="struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c" title="Maximum number of blocks that can be allocated in this pool. Optional. ">VmaPoolCreateInfo::maxBlockCount</a> value that allows multiple memory blocks.</p>
|
|
<h2><a class="anchor" id="linear_algorithm_double_stack"></a>
|
|
Double stack</h2>
|
|
<p>The space reserved by a custom pool with linear algorithm may be used by two stacks:</p>
|
|
<ul>
|
|
<li>First, default one, growing up from offset 0.</li>
|
|
<li>Second, "upper" one, growing down from the end towards lower offsets.</li>
|
|
</ul>
|
|
<p>To make allocation from upper stack, add flag <a class="el" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a42ba3a2d2c7117953210b7c3ef8da0df">VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT</a> to <a class="el" href="struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b" title="Use VmaAllocationCreateFlagBits enum. ">VmaAllocationCreateInfo::flags</a>.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_7_double_stack.png" alt="Double stack"/>
|
|
</div>
|
|
<p>Double stack is available only in pools with one memory block - <a class="el" href="struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c" title="Maximum number of blocks that can be allocated in this pool. Optional. ">VmaPoolCreateInfo::maxBlockCount</a> must be 1. Otherwise behavior is undefined.</p>
|
|
<p>When the two stacks' ends meet so there is not enough space between them for a new allocation, such allocation fails with usual <code>VK_ERROR_OUT_OF_DEVICE_MEMORY</code> error.</p>
|
|
<h2><a class="anchor" id="linear_algorithm_ring_buffer"></a>
|
|
Ring buffer</h2>
|
|
<p>When you free some allocations from the beginning and there is not enough free space for a new one at the end of a pool, allocator's "cursor" wraps around to the beginning and starts allocation there. Thanks to this, if you always release allocations in the same order as you created them (FIFO - First In First Out), you can achieve behavior of a ring buffer / queue.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_5_ring_buffer.png" alt="Ring buffer"/>
|
|
</div>
|
|
<p>Pools with linear algorithm support <a class="el" href="lost_allocations.html">lost allocations</a> when used as ring buffer. If there is not enough free space for a new allocation, but existing allocations from the front of the queue can become lost, they become lost and the allocation succeeds.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Linear_allocator_6_ring_buffer_lost.png" alt="Ring buffer with lost allocations"/>
|
|
</div>
|
|
<p>Ring buffer is available only in pools with one memory block - <a class="el" href="struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c" title="Maximum number of blocks that can be allocated in this pool. Optional. ">VmaPoolCreateInfo::maxBlockCount</a> must be 1. Otherwise behavior is undefined.</p>
|
|
<h1><a class="anchor" id="buddy_algorithm"></a>
|
|
Buddy allocation algorithm</h1>
|
|
<p>There is another allocation algorithm that can be used with custom pools, called "buddy". Its internal data structure is based on a tree of blocks, each having size that is a power of two and a half of its parent's size. When you want to allocate memory of certain size, a free node in the tree is located. If it's too large, it is recursively split into two halves (called "buddies"). However, if requested allocation size is not a power of two, the size of a tree node is aligned up to the nearest power of two and the remaining space is wasted. When two buddy nodes become free, they are merged back into one larger node.</p>
|
|
<div class="image">
|
|
<img src="../gfx/Buddy_allocator.png" alt="Buddy allocator"/>
|
|
</div>
|
|
<p>The advantage of buddy allocation algorithm over default algorithm is faster allocation and deallocation, as well as smaller external fragmentation. The disadvantage is more wasted space (internal fragmentation).</p>
|
|
<p>For more information, please read <a href="https://en.wikipedia.org/wiki/Buddy_memory_allocation">"Buddy memory allocation" on Wikipedia</a> or other sources that describe this concept in general.</p>
|
|
<p>To use buddy allocation algorithm with a custom pool, add flag <a class="el" href="vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a97a0dc38e5161b780594d998d313d35e" title="Enables alternative, buddy allocation algorithm in this pool. ">VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT</a> to <a class="el" href="struct_vma_pool_create_info.html#a8405139f63d078340ae74513a59f5446" title="Use combination of VmaPoolCreateFlagBits. ">VmaPoolCreateInfo::flags</a> while creating <a class="el" href="struct_vma_pool.html" title="Represents custom memory pool. ">VmaPool</a> object.</p>
|
|
<p>Several limitations apply to pools that use buddy algorithm:</p>
|
|
<ul>
|
|
<li>It is recommended to use <a class="el" href="struct_vma_pool_create_info.html#aa4265160536cdb9be821b7686c16c676" title="Size of a single VkDeviceMemory block to be allocated as part of this pool, in bytes. Optional. ">VmaPoolCreateInfo::blockSize</a> that is a power of two. Otherwise, only largest power of two smaller than the size is used for allocations. The remaining space always stays unused.</li>
|
|
<li><a class="el" href="debugging_memory_usage.html#debugging_memory_usage_margins">Margins</a> and <a class="el" href="debugging_memory_usage.html#debugging_memory_usage_corruption_detection">corruption detection</a> don't work in such pools.</li>
|
|
<li><a class="el" href="lost_allocations.html">Lost allocations</a> don't work in such pools. You can use them, but they never become lost. Support may be added in the future.</li>
|
|
<li><a class="el" href="defragmentation.html">Defragmentation</a> doesn't work with allocations made from such pool. </li>
|
|
</ul>
|
|
</div></div><!-- contents -->
|
|
<!-- start footer part -->
|
|
<hr class="footer"/><address class="footer"><small>
|
|
Generated by  <a href="http://www.doxygen.org/index.html">
|
|
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
|
</a> 1.8.14
|
|
</small></address>
|
|
</body>
|
|
</html>
|