mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2024-11-10 10:41:52 +00:00
335 lines
26 KiB
HTML
335 lines
26 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.13"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<title>Vulkan Memory Allocator: Vulkan Memory Allocator</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.13 -->
|
|
<script type="text/javascript">
|
|
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|
</script>
|
|
<script type="text/javascript" src="menudata.js"></script>
|
|
<script type="text/javascript" src="menu.js"></script>
|
|
<script type="text/javascript">
|
|
$(function() {
|
|
initMenu('',true,false,'search.php','Search');
|
|
$(document).ready(function() { init_search(); });
|
|
});
|
|
</script>
|
|
<div id="main-nav"></div>
|
|
</div><!-- top -->
|
|
<!-- 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 class="header">
|
|
<div class="headertitle">
|
|
<div class="title">Vulkan Memory Allocator </div> </div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="toc"><h3>Table of Contents</h3>
|
|
<ul><li class="level1"><a href="#problem">Problem statement</a></li>
|
|
<li class="level1"><a href="#features">Features</a></li>
|
|
<li class="level1"><a href="#prequisites">Prequisites</a></li>
|
|
<li class="level1"><a href="#user_guide">User guide</a><ul><li class="level2"><a href="#quick_start">Quick start</a></li>
|
|
<li class="level2"><a href="#persistently_mapped_memory">Persistently mapped memory</a></li>
|
|
<li class="level2"><a href="#custom_memory_pools">Custom memory pools</a></li>
|
|
<li class="level2"><a href="#defragmentation">Defragmentation</a></li>
|
|
<li class="level2"><a href="#lost_allocations">Lost allocations</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="level1"><a href="#configuration">Configuration</a><ul><li class="level2"><a href="#config_Vulkan_functions">Pointers to Vulkan functions</a></li>
|
|
<li class="level2"><a href="#custom_memory_allocator">Custom host memory allocator</a></li>
|
|
<li class="level2"><a href="#allocation_callbacks">Device memory allocation callbacks</a></li>
|
|
<li class="level2"><a href="#heap_memory_limit">Device heap memory limit</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="level1"><a href="#thread_safety">Thread safety</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="textblock"><p><b>Version 2.0.0-alpha.3</b> (2017-09-12)</p>
|
|
<p>Members grouped: see <a href="modules.html"><b>Modules</b></a>.</p>
|
|
<p>All members: see <a class="el" href="vk__mem__alloc_8h.html">vk_mem_alloc.h</a>.</p>
|
|
<h1><a class="anchor" id="problem"></a>
|
|
Problem statement</h1>
|
|
<p>Memory allocation and resource (buffer and image) creation in Vulkan is difficult (comparing to older graphics API-s, like D3D11 or OpenGL) for several reasons:</p>
|
|
<ul>
|
|
<li>It requires a lot of boilerplate code, just like everything else in Vulkan, because it is a low-level and high-performance API.</li>
|
|
<li>There is additional level of indirection: <code>VkDeviceMemory</code> is allocated separately from creating <code>VkBuffer</code>/<code>VkImage</code> and they must be bound together. The binding cannot be changed later - resource must be recreated.</li>
|
|
<li>Driver must be queried for supported memory heaps and memory types. Different IHV-s provide different types of it.</li>
|
|
<li>It is recommended practice to allocate bigger chunks of memory and assign parts of them to particular resources.</li>
|
|
</ul>
|
|
<h1><a class="anchor" id="features"></a>
|
|
Features</h1>
|
|
<p>This library is helps game developers to manage memory allocations and resource creation by offering some higher-level functions. Features of the library could be divided into several layers, low level to high level:</p>
|
|
<ol type="1">
|
|
<li>Functions that help to choose correct and optimal memory type based on intended usage of the memory.<ul>
|
|
<li>Required or preferred traits of the memory are expressed using higher-level description comparing to Vulkan flags.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Functions that allocate memory blocks, reserve and return parts of them (<code>VkDeviceMemory</code> + offset + size) to the user.<ul>
|
|
<li>Library keeps track of allocated memory blocks, used and unused ranges inside them, finds best matching unused ranges for new allocations, takes all the rules of alignment into consideration.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Functions that can create an image/buffer, allocate memory for it and bind them together - all in one call.</li>
|
|
</ol>
|
|
<h1><a class="anchor" id="prequisites"></a>
|
|
Prequisites</h1>
|
|
<ul>
|
|
<li>Self-contained C++ library in single header file. No external dependencies other than standard C and C++ library and of course Vulkan.</li>
|
|
<li>Public interface in C, in same convention as Vulkan API. Implementation in C++.</li>
|
|
<li>Interface documented using Doxygen-style comments.</li>
|
|
<li>Platform-independent, but developed and tested on Windows using Visual Studio.</li>
|
|
<li>Error handling implemented by returning <code>VkResult</code> error codes - same way as in Vulkan.</li>
|
|
</ul>
|
|
<h1><a class="anchor" id="user_guide"></a>
|
|
User guide</h1>
|
|
<h2><a class="anchor" id="quick_start"></a>
|
|
Quick start</h2>
|
|
<p>In your project code:</p>
|
|
<ol type="1">
|
|
<li>Include "vk_mem_alloc.h" file wherever you want to use the library.</li>
|
|
<li>In exacly one C++ file define following macro before include to build library implementation.</li>
|
|
</ol>
|
|
<pre class="fragment">#define VMA_IMPLEMENTATION
|
|
#include "vk_mem_alloc.h"
|
|
</pre><p>At program startup:</p>
|
|
<ol type="1">
|
|
<li>Initialize Vulkan to have <code>VkPhysicalDevice</code> and <code>VkDevice</code> object.</li>
|
|
<li>Fill <a class="el" href="struct_vma_allocator_create_info.html" title="Description of a Allocator to be created. ">VmaAllocatorCreateInfo</a> structure and create <code>VmaAllocator</code> object by calling <a class="el" href="group__general.html#ga200692051ddb34240248234f5f4c17bb" title="Creates Allocator object. ">vmaCreateAllocator()</a>.</li>
|
|
</ol>
|
|
<pre class="fragment">VmaAllocatorCreateInfo allocatorInfo = {};
|
|
allocatorInfo.physicalDevice = physicalDevice;
|
|
allocatorInfo.device = device;
|
|
|
|
VmaAllocator allocator;
|
|
vmaCreateAllocator(&allocatorInfo, &allocator);
|
|
</pre><p>When you want to create a buffer or image:</p>
|
|
<ol type="1">
|
|
<li>Fill <code>VkBufferCreateInfo</code> / <code>VkImageCreateInfo</code> structure.</li>
|
|
<li>Fill <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> structure.</li>
|
|
<li>Call <a class="el" href="group__layer3.html#gac72ee55598617e8eecca384e746bab51">vmaCreateBuffer()</a> / <a class="el" href="group__layer3.html#ga02a94f25679275851a53e82eacbcfc73" title="Function similar to vmaCreateBuffer(). ">vmaCreateImage()</a> to get <code>VkBuffer</code>/<code>VkImage</code> with memory already allocated and bound to it.</li>
|
|
</ol>
|
|
<pre class="fragment">VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
|
bufferInfo.size = myBufferSize;
|
|
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
|
|
VmaAllocationCreateInfo memReq = {};
|
|
memReq.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
|
|
|
VkBuffer buffer;
|
|
VmaAllocation allocation;
|
|
vmaCreateBuffer(allocator, &bufferInfo, &memReq, &buffer, &allocation, nullptr);
|
|
</pre><p>Don't forget to destroy your objects when no longer needed:</p>
|
|
<pre class="fragment">vmaDestroyBuffer(allocator, buffer, allocation);
|
|
vmaDestroyAllocator(allocator);
|
|
</pre><h2><a class="anchor" id="persistently_mapped_memory"></a>
|
|
Persistently mapped memory</h2>
|
|
<p>If you need to map memory on host, it may happen that two allocations are assigned to the same <code>VkDeviceMemory</code> block, so if you map them both at the same time, it will cause error because mapping single memory block multiple times is illegal in Vulkan.</p>
|
|
<p>It is safer, more convenient and more efficient to use special feature designed for that: persistently mapped memory. Allocations made with <code>VMA_ALLOCATION_CREATE_PERSISTENT_MAP_BIT</code> flag set in <a class="el" href="struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b" title="Use VmaAllocationCreateFlagBits enum. ">VmaAllocationCreateInfo::flags</a> are returned from device memory blocks that stay mapped all the time, so you can just access CPU pointer to it. <a class="el" href="struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2" title="Pointer to the beginning of this allocation as mapped data. Null if this alloaction is not persistent...">VmaAllocationInfo::pMappedData</a> pointer is already offseted to the beginning of particular allocation. Example:</p>
|
|
<pre class="fragment">VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
|
bufCreateInfo.size = 1024;
|
|
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
|
|
VmaAllocationCreateInfo allocCreateInfo = {};
|
|
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
|
|
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_PERSISTENT_MAP_BIT;
|
|
|
|
VkBuffer buf;
|
|
VmaAllocation alloc;
|
|
VmaAllocationInfo allocInfo;
|
|
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
|
|
|
|
.// Buffer is immediately mapped. You can access its memory.
|
|
memcpy(allocInfo.pMappedData, myData, 1024);
|
|
</pre><p>Memory in Vulkan doesn't need to be unmapped before using it e.g. for transfers, but if you are not sure whether it's <code>HOST_COHERENT</code> (here is surely is because it's created with <code>VMA_MEMORY_USAGE_CPU_ONLY</code>), you should check it. If it's not, you should call <code>vkInvalidateMappedMemoryRanges()</code> before reading and <code>vkFlushMappedMemoryRanges()</code> after writing to mapped memory on CPU. Example:</p>
|
|
<pre class="fragment">VkMemoryPropertyFlags memFlags;
|
|
vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags);
|
|
if((memFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
|
|
{
|
|
VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
|
|
memRange.memory = allocInfo.deviceMemory;
|
|
memRange.offset = allocInfo.offset;
|
|
memRange.size = allocInfo.size;
|
|
vkFlushMappedMemoryRanges(device, 1, &memRange);
|
|
}
|
|
</pre><p>For performance reasons it is also recommended to unmap Vulkan memory for the time of call to <code>vkQueueSubmit()</code> or <code>vkQueuePresent()</code>. You can do it for all persistently mapped memory using just one function call. For details, see function <a class="el" href="group__layer2.html#ga26b87244491c1fe77f11fe9ab5779c27" title="Unmaps persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaUnmapPersistentlyMappedMemory()</a>, <a class="el" href="group__layer2.html#ga03366170bb8e186605518d2f5d65b85a" title="Maps back persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaMapPersistentlyMappedMemory()</a>.</p>
|
|
<h2><a class="anchor" id="custom_memory_pools"></a>
|
|
Custom memory pools</h2>
|
|
<p>The library automatically creates and manages default memory pool for each memory type available on the device. A pool contains a number of <code>VkDeviceMemory</code> blocks. 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 size of Vulkan memory blocks.</li>
|
|
<li>Limit maximum amount of Vulkan memory allocated 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="group__layer2.html#ga5c8770ded7c59c8caac6de0c2cb00b50" title="Allocates Vulkan device memory and creates VmaPool object. ">vmaCreatePool()</a> to obtain <code>VmaPool</code> 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 usage.</li>
|
|
</ol>
|
|
<p>Example:</p>
|
|
<pre class="fragment">.// Create a pool that could have at most 2 blocks, 128 MB each.
|
|
VmaPoolCreateInfo poolCreateInfo = {};
|
|
poolCreateInfo.memoryTypeIndex = ...
|
|
poolCreateInfo.blockSize = 128ull * 1024 * 1024;
|
|
poolCreateInfo.maxBlockCount = 2;
|
|
|
|
VmaPool pool;
|
|
vmaCreatePool(allocator, &poolCreateInfo, &pool);
|
|
|
|
.// Allocate a buffer out of it.
|
|
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
|
bufCreateInfo.size = 1024;
|
|
bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
|
|
VmaAllocationCreateInfo allocCreateInfo = {};
|
|
allocCreateInfo.pool = pool;
|
|
|
|
VkBuffer buf;
|
|
VmaAllocation alloc;
|
|
VmaAllocationInfo allocInfo;
|
|
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
|
|
</pre><p>You have to free all allocations made from this pool before destroying it.</p>
|
|
<pre class="fragment">vmaDestroyBuffer(allocator, buf, alloc);
|
|
vmaDestroyPool(allocator, pool);
|
|
</pre><h2><a class="anchor" id="defragmentation"></a>
|
|
Defragmentation</h2>
|
|
<p>Interleaved allocations and deallocations of many objects of varying size can cause fragmentation, 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 <a class="el" href="group__layer2.html#ga6aced90fcc7b39882b6654a740a0b9bb" title="Compacts memory by moving allocations. ">vmaDefragment()</a>. Given set of allocations, this function can move them to compact used memory, ensure more continuous free space and possibly also free some <code>VkDeviceMemory</code>. It can work only on allocations made from memory type that is <code>HOST_VISIBLE</code>. Allocations are modified to point to the new <code>VkDeviceMemory</code> and offset. Data in this memory is also <code>memmove</code>-ed to the new place. However, if you have images or buffers bound to these allocations (and you certainly do), you need to destroy, recreate, and bind them to the new place in memory.</p>
|
|
<p>For further details and example code, see documentation of function <a class="el" href="group__layer2.html#ga6aced90fcc7b39882b6654a740a0b9bb" title="Compacts memory by moving allocations. ">vmaDefragment()</a>.</p>
|
|
<h2><a class="anchor" id="lost_allocations"></a>
|
|
Lost allocations</h2>
|
|
<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 <code>VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</code> flag in <a class="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 <a class="el" href="group__layer2.html#ga86dd08aba8633bfa4ad0df2e76481d8b" title="Returns current information about specified allocation. ">vmaGetAllocationInfo()</a> and see if <a class="el" href="struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67" title="Handle to Vulkan memory object. ">VmaAllocationInfo::deviceMemory</a> is not <code>VK_NULL_HANDLE</code>. 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.</p>
|
|
<p>To create an allocation that can make some other allocations lost to make room for it, use <code>VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</code> flag. You will usually use both flags <code>VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</code> and <code>VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</code> at the same time.</p>
|
|
<p>Warning! Current implementation uses quite naive, brute force algorithm, which can make allocation calls that use <code>VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</code> flag quite slow. A new, more optimal algorithm and data structure to speed this up is planned for the future.</p>
|
|
<p><b>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 <a class="el" href="group__layer2.html#ga86dd08aba8633bfa4ad0df2e76481d8b" title="Returns current information about specified allocation. ">vmaGetAllocationInfo()</a> not only returns allocation 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>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 <a class="el" href="group__layer2.html#ga86dd08aba8633bfa4ad0df2e76481d8b" title="Returns current information about specified allocation. ">vmaGetAllocationInfo()</a> will not become lost for a number of additional frames back from the current one by specifying this number as <a class="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 <a class="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><b>How do you inform the library when new frame starts?</b></p>
|
|
<p>You need to call function <a class="el" href="group__general.html#gade56bf8dc9f5a5eaddf5f119ed525236" title="Sets index of the current frame. ">vmaSetCurrentFrameIndex()</a>.</p>
|
|
<p>Example code:</p>
|
|
<pre class="fragment">struct MyBuffer
|
|
{
|
|
VkBuffer m_Buf = nullptr;
|
|
VmaAllocation m_Alloc = nullptr;
|
|
|
|
.// Called when the buffer is really needed in the current frame.
|
|
void EnsureBuffer();
|
|
};
|
|
|
|
void MyBuffer::EnsureBuffer()
|
|
{
|
|
.// Buffer has been created.
|
|
if(m_Buf != VK_NULL_HANDLE)
|
|
{
|
|
.// Check if its allocation is not lost + mark it as used in current frame.
|
|
VmaAllocationInfo allocInfo;
|
|
vmaGetAllocationInfo(allocator, m_Alloc, &allocInfo);
|
|
if(allocInfo.deviceMemory != VK_NULL_HANDLE)
|
|
{
|
|
.// It's all OK - safe to use m_Buf.
|
|
return;
|
|
}
|
|
}
|
|
|
|
.// Buffer not yet exists or lost - destroy and recreate it.
|
|
|
|
vmaDestroyBuffer(allocator, m_Buf, m_Alloc);
|
|
|
|
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
|
bufCreateInfo.size = 1024;
|
|
bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
|
|
VmaAllocationCreateInfo allocCreateInfo = {};
|
|
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
|
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT |
|
|
VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;
|
|
|
|
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, nullptr);
|
|
}
|
|
</pre><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>The library uses following algorithm for allocation, in order:</p>
|
|
<ol type="1">
|
|
<li>Try to find free range of memory in existing blocks.</li>
|
|
<li>If failed, try to create a new block of <code>VkDeviceMemory</code>, with preferred block size.</li>
|
|
<li>If failed, try to create such block with size/2 and size/4.</li>
|
|
<li>If failed and <code>VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</code> flag was specified, try to find space in existing blocks, possilby making some other allocations lost.</li>
|
|
<li>If failed, try to allocate separate <code>VkDeviceMemory</code> for this allocation, just like when you use <code>VMA_ALLOCATION_CREATE_OWN_MEMORY_BIT</code>.</li>
|
|
<li>If failed, choose other memory type that meets the requirements specified in <a class="el" href="struct_vma_allocation_create_info.html">VmaAllocationCreateInfo</a> and go to point 1.</li>
|
|
<li>If failed, return <code>VK_ERROR_OUT_OF_DEVICE_MEMORY</code>.</li>
|
|
</ol>
|
|
<h1><a class="anchor" id="configuration"></a>
|
|
Configuration</h1>
|
|
<p>Please check "CONFIGURATION SECTION" in the code to find macros that you can define before each <code>#include</code> of this file or change directly in this file to provide your own implementation of basic facilities like assert, <code>min()</code> and <code>max()</code> functions, mutex etc. C++ STL is used by default, but changing these allows you to get rid of any STL usage if you want, as many game developers tend to do.</p>
|
|
<h2><a class="anchor" id="config_Vulkan_functions"></a>
|
|
Pointers to Vulkan functions</h2>
|
|
<p>The library uses Vulkan functions straight from the <code>vulkan.h</code> header by default. If you want to provide your own pointers to these functions, e.g. fetched using <code>vkGetInstanceProcAddr</code> and <code>vkGetDeviceProcAddr</code>:</p>
|
|
<ol type="1">
|
|
<li>Remove macro <code>VMA_STATIC_VULKAN_FUNCTIONS</code> from "CONFIGURATION SECTION" section.</li>
|
|
<li>Provide valid pointers through <a class="el" href="struct_vma_allocator_create_info.html#a3dc197be3227da7338b1643f70db36bd" title="Pointers to Vulkan functions. Can be null if you leave #define VMA_STATIC_VULKAN_FUNCTIONS 1...">VmaAllocatorCreateInfo::pVulkanFunctions</a>.</li>
|
|
</ol>
|
|
<h2><a class="anchor" id="custom_memory_allocator"></a>
|
|
Custom host memory allocator</h2>
|
|
<p>If you use custom allocator for CPU memory rather than default operator <code>new</code> and <code>delete</code> from C++, you can make this library using your allocator as well by filling optional member <a class="el" href="struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d" title="Custom CPU memory allocation callbacks. ">VmaAllocatorCreateInfo::pAllocationCallbacks</a>. These functions will be passed to Vulkan, as well as used by the library itself to make any CPU-side allocations.</p>
|
|
<h2><a class="anchor" id="allocation_callbacks"></a>
|
|
Device memory allocation callbacks</h2>
|
|
<p>The library makes calls to <code>vkAllocateMemory()</code> and <code>vkFreeMemory()</code> internally. You can setup callbacks to be informed about these calls, e.g. for the purpose of gathering some statistics. To do it, fill optional member <a class="el" href="struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e" title="Informative callbacks for vkAllocateMemory, vkFreeMemory. ">VmaAllocatorCreateInfo::pDeviceMemoryCallbacks</a>.</p>
|
|
<h2><a class="anchor" id="heap_memory_limit"></a>
|
|
Device heap memory limit</h2>
|
|
<p>If you want to test how your program behaves with limited amount of Vulkan device memory available (without switching your graphics card to one that really has smaller VRAM), you can use a feature of this library intended for this purpose. To do it, fill optional member <a class="el" href="struct_vma_allocator_create_info.html#a31c192aa6cbffa33279f6d9f0c47c44b" title="Either NULL or a pointer to an array of limits on maximum number of bytes that can be allocated out o...">VmaAllocatorCreateInfo::pHeapSizeLimit</a>.</p>
|
|
<h1><a class="anchor" id="thread_safety"></a>
|
|
Thread safety</h1>
|
|
<ul>
|
|
<li>The library has no global state, so separate <code>VmaAllocator</code> objects can be used independently.</li>
|
|
<li>By default, all calls to functions that take <code>VmaAllocator</code> as first parameter are safe to call from multiple threads simultaneously because they are synchronized internally when needed.</li>
|
|
<li>When the allocator is created with <code>VMA_ALLOCATOR_EXTERNALLY_SYNCHRONIZED_BIT</code> flag, calls to functions that take such <code>VmaAllocator</code> object must be synchronized externally.</li>
|
|
<li>Access to a <code>VmaAllocation</code> object must be externally synchronized. For example, you must not call <a class="el" href="group__layer2.html#ga86dd08aba8633bfa4ad0df2e76481d8b" title="Returns current information about specified allocation. ">vmaGetAllocationInfo()</a> and <a class="el" href="group__layer2.html#ga6aced90fcc7b39882b6654a740a0b9bb" title="Compacts memory by moving allocations. ">vmaDefragment()</a> from different threads at the same time if you pass the same <code>VmaAllocation</code> object to these functions. </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.13
|
|
</small></address>
|
|
</body>
|
|
</html>
|