<divclass="textblock"><p>Interleaved allocations and deallocations of many objects of varying size can cause fragmentation over time, which can lead to a situation where the library is unable to find a continuous range of free memory for a new allocation despite there is enough free space, just scattered across many small free ranges between existing allocations.</p>
<p>To mitigate this problem, you can use defragmentation feature. It doesn't happen automatically though and needs your cooperation, because VMA is a low level library that only allocates memory. It cannot recreate buffers and images in a new place as it doesn't remember the contents of <code>VkBufferCreateInfo</code> / <code>VkImageCreateInfo</code> structures. It cannot copy their contents as it doesn't record any commands to a command buffer.</p>
<divclass="line"><spanclass="keywordflow">for</span>(uint32_t i = 0; i < pass.<aclass="code hl_variable"href="struct_vma_defragmentation_pass_move_info.html#a1b3e18c23f9691f35baf183e615c4408">moveCount</a>; ++i)</div>
<divclass="line"><spanclass="comment">// Make sure the copy commands finished executing.</span></div>
<divclass="line"> vkWaitForFences(...);</div>
<divclass="line"></div>
<divclass="line"><spanclass="comment">// Destroy old buffers/images bound with pass.pMoves[i].srcAllocation.</span></div>
<divclass="line"><spanclass="keywordflow">for</span>(uint32_t i = 0; i < pass.<aclass="code hl_variable"href="struct_vma_defragmentation_pass_move_info.html#a1b3e18c23f9691f35baf183e615c4408">moveCount</a>; ++i)</div>
<divclass="ttc"id="agroup__group__alloc_html_ga86dd08aba8633bfa4ad0df2e76481d8b"><divclass="ttname"><ahref="group__group__alloc.html#ga86dd08aba8633bfa4ad0df2e76481d8b">vmaGetAllocationInfo</a></div><divclass="ttdeci">void vmaGetAllocationInfo(VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)</div><divclass="ttdoc">Returns current information about specified allocation.</div></div>
<divclass="ttc"id="astruct_vma_allocation_info_html_adc507656149c04de7ed95d0042ba2a13"><divclass="ttname"><ahref="struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13">VmaAllocationInfo::pUserData</a></div><divclass="ttdeci">void * pUserData</div><divclass="ttdoc">Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vma...</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1411</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_context_html"><divclass="ttname"><ahref="struct_vma_defragmentation_context.html">VmaDefragmentationContext</a></div><divclass="ttdoc">An opaque object that represents started defragmentation process.</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_info_html"><divclass="ttname"><ahref="struct_vma_defragmentation_info.html">VmaDefragmentationInfo</a></div><divclass="ttdoc">Parameters for defragmentation.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1454</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_info_html_a18dd2097d8ab2976cdc7dd3e7b978bd4"><divclass="ttname"><ahref="struct_vma_defragmentation_info.html#a18dd2097d8ab2976cdc7dd3e7b978bd4">VmaDefragmentationInfo::pool</a></div><divclass="ttdeci">VmaPool pool</div><divclass="ttdoc">Custom pool to be defragmented.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1461</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_info_html_a3e23080c978ecf3abb3180f5b2069da7"><divclass="ttname"><ahref="struct_vma_defragmentation_info.html#a3e23080c978ecf3abb3180f5b2069da7">VmaDefragmentationInfo::flags</a></div><divclass="ttdeci">VmaDefragmentationFlags flags</div><divclass="ttdoc">Use combination of VmaDefragmentationFlagBits.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1456</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_move_html_a25aa1bb64efc507a49c6cbc50689f862"><divclass="ttname"><ahref="struct_vma_defragmentation_move.html#a25aa1bb64efc507a49c6cbc50689f862">VmaDefragmentationMove::srcAllocation</a></div><divclass="ttdeci">VmaAllocation srcAllocation</div><divclass="ttdoc">Allocation that should be moved.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1487</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_move_html_ab65b106adf209acd7313296d1075300e"><divclass="ttname"><ahref="struct_vma_defragmentation_move.html#ab65b106adf209acd7313296d1075300e">VmaDefragmentationMove::dstTmpAllocation</a></div><divclass="ttdeci">VmaAllocation dstTmpAllocation</div><divclass="ttdoc">Temporary allocation pointing to destination memory that will replace srcAllocation.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1494</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_pass_move_info_html"><divclass="ttname"><ahref="struct_vma_defragmentation_pass_move_info.html">VmaDefragmentationPassMoveInfo</a></div><divclass="ttdoc">Parameters for incremental defragmentation steps.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1502</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_pass_move_info_html_a1b3e18c23f9691f35baf183e615c4408"><divclass="ttname"><ahref="struct_vma_defragmentation_pass_move_info.html#a1b3e18c23f9691f35baf183e615c4408">VmaDefragmentationPassMoveInfo::moveCount</a></div><divclass="ttdeci">uint32_t moveCount</div><divclass="ttdoc">Number of elements in the pMoves array.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1504</div></div>
<divclass="ttc"id="astruct_vma_defragmentation_pass_move_info_html_adfa7a4994afd9b940e7f1dfaf436a725"><divclass="ttname"><ahref="struct_vma_defragmentation_pass_move_info.html#adfa7a4994afd9b940e7f1dfaf436a725">VmaDefragmentationPassMoveInfo::pMoves</a></div><divclass="ttdeci">VmaDefragmentationMove * pMoves</div><divclass="ttdoc">Array of moves to be performed by the user in the current defragmentation pass.</div><divclass="ttdef"><b>Definition</b> vk_mem_alloc.h:1528</div></div>
</div><!-- fragment --><p>Although functions like <aclass="el"href="group__group__alloc.html#gac72ee55598617e8eecca384e746bab51"title="Creates a new VkBuffer, allocates and binds memory for it.">vmaCreateBuffer()</a>, <aclass="el"href="group__group__alloc.html#ga02a94f25679275851a53e82eacbcfc73"title="Function similar to vmaCreateBuffer().">vmaCreateImage()</a>, <aclass="el"href="group__group__alloc.html#ga0d9f4e4ba5bf9aab1f1c746387753d77"title="Destroys Vulkan buffer and frees allocated memory.">vmaDestroyBuffer()</a>, <aclass="el"href="group__group__alloc.html#gae50d2cb3b4a3bfd4dd40987234e50e7e"title="Destroys Vulkan image and frees allocated memory.">vmaDestroyImage()</a> create/destroy an allocation and a buffer/image at once, these are just a shortcut for creating the resource, allocating memory, and binding them together. Defragmentation works on memory allocations only. You must handle the rest manually. Defragmentation is an iterative process that should repreat "passes" as long as related functions return <code>VK_INCOMPLETE</code> not <code>VK_SUCCESS</code>. In each pass:</p>
<li><aclass="el"href="group__group__alloc.html#ga980d7da2ce3b1fd5c8b8476bc362cc00"title="Starts single defragmentation pass.">vmaBeginDefragmentationPass()</a> function call:<ul>
<li>Calculates and returns the list of allocations to be moved in this pass. Note this can be a time-consuming process.</li>
<li>Reserves destination memory for them by creating temporary destination allocations that you can query for their <code>VkDeviceMemory</code> + offset using <aclass="el"href="group__group__alloc.html#ga86dd08aba8633bfa4ad0df2e76481d8b"title="Returns current information about specified allocation.">vmaGetAllocationInfo()</a>.</li>
<li>Copy data from source to destination resources if necessary.</li>
<li>Destroy the source buffers/images, but NOT their allocations.</li>
</ul>
</li>
<li><aclass="el"href="group__group__alloc.html#gaded05a445742a00718ee766144c5c226"title="Ends single defragmentation pass.">vmaEndDefragmentationPass()</a> function call:<ul>
<li>Frees the source memory reserved for the allocations that are moved.</li>
<li>Modifies source <aclass="el"href="struct_vma_allocation.html"title="Represents single memory allocation.">VmaAllocation</a> objects that are moved to point to the destination reserved memory.</li>
<p>Unlike in previous iterations of the defragmentation API, there is no list of "movable" allocations passed as a parameter. Defragmentation algorithm tries to move all suitable allocations. You can, however, refuse to move some of them inside a defragmentation pass, by setting <code>pass.pMoves[i].operation</code> to <aclass="el"href="group__group__alloc.html#ggada9e3861caf96f08894b0bcc160ec257ad25bc6f816b226b4fd5170e845f218d2"title="Set this value if you cannot move the allocation. New place reserved at dstTmpAllocation will be free...">VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE</a>. This is not recommended and may result in suboptimal packing of the allocations after defragmentation. If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.</p>
<p>Inside a pass, for each allocation that should be moved:</p>
<li>You should copy its data from the source to the destination place by calling e.g. <code>vkCmdCopyBuffer()</code>, <code>vkCmdCopyImage()</code>.<ul>
<li>You need to make sure these commands finished executing before destroying the source buffers/images and before calling <aclass="el"href="group__group__alloc.html#gaded05a445742a00718ee766144c5c226"title="Ends single defragmentation pass.">vmaEndDefragmentationPass()</a>.</li>
</ul>
</li>
<li>If a resource doesn't contain any meaningful data, e.g. it is a transient color attachment image to be cleared, filled, and used temporarily in each rendering frame, you can just recreate this image without copying its data.</li>
<li>If the resource is in <code>HOST_VISIBLE</code> and <code>HOST_CACHED</code> memory, you can copy its data on the CPU using <code>memcpy()</code>.</li>
<li>If you cannot move the allocation, you can set <code>pass.pMoves[i].operation</code> to <aclass="el"href="group__group__alloc.html#ggada9e3861caf96f08894b0bcc160ec257ad25bc6f816b226b4fd5170e845f218d2"title="Set this value if you cannot move the allocation. New place reserved at dstTmpAllocation will be free...">VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE</a>. This will cancel the move.<ul>
<li><aclass="el"href="group__group__alloc.html#gaded05a445742a00718ee766144c5c226"title="Ends single defragmentation pass.">vmaEndDefragmentationPass()</a> will then free the destination memory not the source memory of the allocation, leaving it unchanged.</li>
</ul>
</li>
<li>If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time), you can set <code>pass.pMoves[i].operation</code> to <aclass="el"href="group__group__alloc.html#ggada9e3861caf96f08894b0bcc160ec257a9786f8492a9be2c03bd26395e352ab85"title="Set this value if you decide to abandon the allocation and you destroyed the buffer/image....">VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY</a>.<ul>
<li><aclass="el"href="group__group__alloc.html#gaded05a445742a00718ee766144c5c226"title="Ends single defragmentation pass.">vmaEndDefragmentationPass()</a> will then free both source and destination memory, and will destroy the source <aclass="el"href="struct_vma_allocation.html"title="Represents single memory allocation.">VmaAllocation</a> object.</li>
<p>You can defragment a specific custom pool by setting <aclass="el"href="struct_vma_defragmentation_info.html#a18dd2097d8ab2976cdc7dd3e7b978bd4"title="Custom pool to be defragmented.">VmaDefragmentationInfo::pool</a> (like in the example above) or all the default pools by setting this member to null.</p>
<p>Defragmentation is always performed in each pool separately. Allocations are never moved between different Vulkan memory types. The size of the destination memory reserved for a moved allocation is the same as the original one. Alignment of an allocation as it was determined using <code>vkGetBufferMemoryRequirements()</code> etc. is also respected after defragmentation. Buffers/images should be recreated with the same <code>VkBufferCreateInfo</code> / <code>VkImageCreateInfo</code> parameters as the original ones.</p>
<p>You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved in each pass, e.g. to call it in sync with render frames and not to experience too big hitches. See members: <aclass="el"href="struct_vma_defragmentation_info.html#a637ada77b02179a27fa92290000afac4"title="Maximum numbers of bytes that can be copied during single pass, while moving allocations to different...">VmaDefragmentationInfo::maxBytesPerPass</a>, <aclass="el"href="struct_vma_defragmentation_info.html#ac2db29d309bebc4f7d55041416e9694b"title="Maximum number of allocations that can be moved during single pass to a different place.">VmaDefragmentationInfo::maxAllocationsPerPass</a>.</p>
<p>It is also safe to perform the defragmentation asynchronously to render frames and other Vulkan and VMA usage, possibly from multiple threads, with the exception that allocations returned in <aclass="el"href="struct_vma_defragmentation_pass_move_info.html#adfa7a4994afd9b940e7f1dfaf436a725"title="Array of moves to be performed by the user in the current defragmentation pass.">VmaDefragmentationPassMoveInfo::pMoves</a> shouldn't be destroyed until the defragmentation pass is ended.</p>
<p><b>Mapping</b> is preserved on allocations that are moved during defragmentation. Whether through <aclass="el"href="group__group__alloc.html#ggad9889c10c798b040d59c92f257cae597a11da372cc3a82931c5e5d6146cd9dd1f"title="Set this flag to use a memory that will be persistently mapped and retrieve pointer to it.">VMA_ALLOCATION_CREATE_MAPPED_BIT</a> or <aclass="el"href="group__group__alloc.html#gad5bd1243512d099706de88168992f069"title="Maps memory represented by given allocation and returns pointer to it.">vmaMapMemory()</a>, the allocations are mapped at their new place. Of course, pointer to the mapped data changes, so it needs to be queried using <aclass="el"href="struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2"title="Pointer to the beginning of this allocation as mapped data.">VmaAllocationInfo::pMappedData</a>.</p>
<dlclass="section note"><dt>Note</dt><dd>Defragmentation is not supported in custom pools created with <aclass="el"href="group__group__alloc.html#gga9a7c45f9c863695d98c83fa5ac940fe7a13c8a444197c67866be9cb05599fc726"title="Enables alternative, linear allocation algorithm in this pool.">VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT</a>. </dd></dl>