<divclass="textblock"><p>If your game oversubscribes video memory, if may work OK in previous-generation graphics APIs (DirectX 9, 10, 11, OpenGL) because resources are automatically paged to system RAM. In Vulkan you can't do it because when you run out of memory, an allocation just fails. If you have more data (e.g. textures) that can fit into VRAM and you don't need it all at once, you may want to upload them to GPU on demand and "push out" ones that are not used for a long time to make room for the new ones, effectively using VRAM (or a cartain memory pool) as a form of cache. Vulkan Memory Allocator can help you with that by supporting a concept of "lost allocations".</p>
<p>To create an allocation that can become lost, include <aclass="el"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2">VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</a> flag in <aclass="el"href="struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b"title="Use VmaAllocationCreateFlagBits enum.">VmaAllocationCreateInfo::flags</a>. Before using a buffer or image bound to such allocation in every new frame, you need to query it if it's not lost. To check it, call <aclass="el"href="vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a"title="Returns VK_TRUE if allocation is not lost and atomically marks it as used in current frame.">vmaTouchAllocation()</a>. If the allocation is lost, you should not use it or buffer/image bound to it. You mustn't forget to destroy this allocation and this buffer/image. <aclass="el"href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b"title="Returns current information about specified allocation and atomically marks it as used in current fra...">vmaGetAllocationInfo()</a> can also be used for checking status of the allocation. Allocation is lost when returned <aclass="el"href="struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67"title="Handle to Vulkan memory object.">VmaAllocationInfo::deviceMemory</a> == <code>VK_NULL_HANDLE</code>.</p>
<p>To create an allocation that can make some other allocations lost to make room for it, use <aclass="el"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e">VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</a> flag. You will usually use both flags <aclass="el"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e">VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</a> and <aclass="el"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2">VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</a> at the same time.</p>
<p>Warning! Current implementation uses quite naive, brute force algorithm, which can make allocation calls that use <aclass="el"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e">VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</a> flag quite slow. A new, more optimal algorithm and data structure to speed this up is planned for the future.</p>
<p><b>Q: When interleaving creation of new allocations with usage of existing ones, how do you make sure that an allocation won't become lost while it's used in the current frame?</b></p>
<p>It is ensured because <aclass="el"href="vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a"title="Returns VK_TRUE if allocation is not lost and atomically marks it as used in current frame.">vmaTouchAllocation()</a> / <aclass="el"href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b"title="Returns current information about specified allocation and atomically marks it as used in current fra...">vmaGetAllocationInfo()</a> not only returns allocation status/parameters and checks whether it's not lost, but when it's not, it also atomically marks it as used in the current frame, which makes it impossible to become lost in that frame. It uses lockless algorithm, so it works fast and doesn't involve locking any internal mutex.</p>
<p><b>Q: What if my allocation may still be in use by the GPU when it's rendering a previous frame while I already submit new frame on the CPU?</b></p>
<p>You can make sure that allocations "touched" by <aclass="el"href="vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a"title="Returns VK_TRUE if allocation is not lost and atomically marks it as used in current frame.">vmaTouchAllocation()</a> / <aclass="el"href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b"title="Returns current information about specified allocation and atomically marks it as used in current fra...">vmaGetAllocationInfo()</a> will not become lost for a number of additional frames back from the current one by specifying this number as <aclass="el"href="struct_vma_allocator_create_info.html#a21ea188dd212b8171cb9ecbed4a2a3a7"title="Maximum number of additional frames that are in use at the same time as current frame.">VmaAllocatorCreateInfo::frameInUseCount</a> (for default memory pool) and <aclass="el"href="struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa"title="Maximum number of additional frames that are in use at the same time as current frame.">VmaPoolCreateInfo::frameInUseCount</a> (for custom pool).</p>
<p>You need to call function <aclass="el"href="vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236"title="Sets index of the current frame.">vmaSetCurrentFrameIndex()</a>.</p>
<divclass="fragment"><divclass="line"><spanclass="keyword">struct </span>MyBuffer</div><divclass="line">{</div><divclass="line"> VkBuffer m_Buf = <spanclass="keyword">nullptr</span>;</div><divclass="line"><aclass="code"href="struct_vma_allocation.html">VmaAllocation</a> m_Alloc = <spanclass="keyword">nullptr</span>;</div><divclass="line"></div><divclass="line"><spanclass="comment">// Called when the buffer is really needed in the current frame.</span></div><divclass="line"><spanclass="keywordtype">void</span> EnsureBuffer();</div><divclass="line">};</div><divclass="line"></div><divclass="line"><spanclass="keywordtype">void</span> MyBuffer::EnsureBuffer()</div><divclass="line">{</div><divclass="line"><spanclass="comment">// Buffer has been created.</span></div><divclass="line"><spanclass="keywordflow">if</span>(m_Buf != VK_NULL_HANDLE)</div><divclass="line"> {</div><divclass="line"><spanclass="comment">// Check if its allocation is not lost + mark it as used in current frame.</span></div><divclass="line"><spanclass="keywordflow">if</span>(<aclass="code"href="vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a">vmaTouchAllocation</a>(allocator, m_Alloc))</div><divclass="line"> {</div><divclass="line"><spanclass="comment">// It's all OK - safe to use m_Buf.</span></div><divclass="line"><spanclass="keywordflow">return</span>;</div><divclass="line"> }</div><divclass="line"> }</div><divclass="line"></div><divclass="line"><spanclass="comment">// Buffer not yet exists or lost - destroy and recreate it.</span></div><divclass="line"></div><divclass="line"><aclass="code"href="vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77">vmaDestroyBuffer</a>(allocator, m_Buf, m_Alloc);</div><divclass="line"></div><divclass="line"> VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };</div><divclass="line"> bufCreateInfo.size = 1024;</div><divclass="line"> bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;</div><divclass="line"></div><divclass="line"><aclass="code"href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> allocCreateInfo = {};</div><divclass="line"> allocCreateInfo.<aclass="code"href="struct_vma_allocation_create_info.html#accb8b06b1f677d858cb9af20705fa910">usage</a> = <aclass="code"href="vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7">VMA_MEMORY_USAGE_GPU_ONLY</a>;</div><divclass="line"> allocCreateInfo.<aclass="code"href="struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b">flags</a> = <aclass="code"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2">VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</a> |</div><divclass="line"><aclass="code"href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e">VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</a>;</div><divclass="line"></div><divclass="line"><aclass="code"href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer</a>(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, <spanclass="keyword">nullptr</span>);</div><divclass="line">}</div></div><!-- fragment --><p>When using lost allocations, you may see some Vulkan validation layer warnings about overlapping regions of memory bound to different kinds of buffers and images. This is still valid as long as you implement proper handling of lost allocations (like in the example above) and don't use them.</p>
<p>You can create an allocation that is already in lost state from the beginning using function <aclass="el"href="vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1"title="Creates new allocation that is in lost state from the beginning.">vmaCreateLostAllocation()</a>. It may be useful if you need a "dummy" allocation that is not null.</p>
<p>You can call function <aclass="el"href="vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024"title="Marks all allocations in given pool as lost if they are not used in current frame or VmaPoolCreateInf...">vmaMakePoolAllocationsLost()</a> to set all eligible allocations in a specified custom pool to lost state. Allocations that have been "touched" in current frame or <aclass="el"href="struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa"title="Maximum number of additional frames that are in use at the same time as current frame.">VmaPoolCreateInfo::frameInUseCount</a> frames back cannot become lost.</p>
<p>Yes, although it has no visible effect. Calls to <aclass="el"href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b"title="Returns current information about specified allocation and atomically marks it as used in current fra...">vmaGetAllocationInfo()</a> and <aclass="el"href="vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a"title="Returns VK_TRUE if allocation is not lost and atomically marks it as used in current frame.">vmaTouchAllocation()</a> update last use frame index also for allocations that cannot become lost, but the only way to observe it is to dump internal allocator state using <aclass="el"href="vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0"title="Builds and returns statistics as string in JSON format.">vmaBuildStatsString()</a>. You can use this feature for debugging purposes to explicitly mark allocations that you use in current frame and then analyze JSON dump to see for how long each allocation stays unused. </p>