mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-12-25 18:31:05 +00:00
Improvements in documentation formatting.
This commit is contained in:
parent
c005a84e37
commit
07a7deb09d
@ -82,6 +82,8 @@ $(function() {
|
||||
<p>Other members of this structure can be null as long as you leave <code>VMA_STATIC_VULKAN_FUNCTIONS</code> defined to 1, which is the default.</p>
|
||||
<div class="fragment"><div class="line"><a class="code" href="struct_vma_vulkan_functions.html">VmaVulkanFunctions</a> vulkanFunctions = {};</div><div class="line">vulkanFunctions.<a class="code" href="struct_vma_vulkan_functions.html#a9d8d1b05d2b1e7e1d9b27f6f585acf9c">vkGetBufferMemoryRequirements2KHR</a> =</div><div class="line"> (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(device, <span class="stringliteral">"vkGetBufferMemoryRequirements2KHR"</span>);</div><div class="line">vulkanFunctions.<a class="code" href="struct_vma_vulkan_functions.html#a9cdcdc1e2b2ea7c571f7d27e30ba6875">vkGetImageMemoryRequirements2KHR</a> =</div><div class="line"> (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(device, <span class="stringliteral">"vkGetImageMemoryRequirements2KHR"</span>);</div><div class="line"> </div><div class="line"><a class="code" href="struct_vma_allocator_create_info.html">VmaAllocatorCreateInfo</a> allocatorInfo = {};</div><div class="line">allocatorInfo.<a class="code" href="struct_vma_allocator_create_info.html#a3dc197be3227da7338b1643f70db36bd">pVulkanFunctions</a> = &vulkanFunctions;</div><div class="line"><span class="comment">// Fill other members of allocatorInfo...</span></div></div><!-- fragment --><p>3 . Use <code>VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT</code> flag when creating your <code>VmaAllocator</code> to inform the library that you enabled required extensions and you want the library to use them.</p>
|
||||
<div class="fragment"><div class="line">allocatorInfo.<a class="code" href="struct_vma_allocator_create_info.html#a392ea2ecbaff93f91a7c49f735ad4346">flags</a> |= <a class="code" href="vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cace7da7cc6e71a625dfa763c55a597878">VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT</a>;</div><div class="line"></div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb">vmaCreateAllocator</a>(&allocatorInfo, &allocator);</div></div><!-- fragment --><p>That's all. The extension will be automatically used whenever you create a buffer using <a class="el" href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer()</a> or image using <a class="el" href="vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73" title="Function similar to vmaCreateBuffer(). ">vmaCreateImage()</a>.</p>
|
||||
<p>When using the extension together with Vulkan Validation Layer, you will receive warnings like this: </p><pre class="fragment">vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer.
|
||||
</pre><p>It is OK, you should just ignore it. It happens because you use function <code>vkGetBufferMemoryRequirements2KHR()</code> instead of standard <code>vkGetBufferMemoryRequirements()</code>, while the validation layer seems to be unaware of it.</p>
|
||||
<p>To learn more about this extension, see:</p>
|
||||
<ul>
|
||||
<li><a href="https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VK_KHR_dedicated_allocation">VK_KHR_dedicated_allocation in Vulkan specification</a></li>
|
||||
|
@ -79,30 +79,8 @@ $(function() {
|
||||
<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> </div></div><!-- contents -->
|
||||
<div class="fragment"><div class="line"><span class="comment">// Create a pool that could have at most 2 blocks, 128 MB 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">VmaPool 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">VmaAllocation 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 --> </div></div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
|
@ -77,46 +77,7 @@ $(function() {
|
||||
<p><b>How do you inform the library when new frame starts?</b></p>
|
||||
<p>You need to call function <a class="el" href="vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236" 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>
|
||||
<div class="fragment"><div class="line"><span class="keyword">struct </span>MyBuffer</div><div class="line">{</div><div class="line"> VkBuffer m_Buf = <span class="keyword">nullptr</span>;</div><div class="line"> VmaAllocation m_Alloc = <span class="keyword">nullptr</span>;</div><div class="line"></div><div class="line"> <span class="comment">// Called when the buffer is really needed in the current frame.</span></div><div class="line"> <span class="keywordtype">void</span> EnsureBuffer();</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> MyBuffer::EnsureBuffer()</div><div class="line">{</div><div class="line"> <span class="comment">// Buffer has been created.</span></div><div class="line"> <span class="keywordflow">if</span>(m_Buf != VK_NULL_HANDLE)</div><div class="line"> {</div><div class="line"> <span class="comment">// Check if its allocation is not lost + mark it as used in current frame.</span></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#a86dd08aba8633bfa4ad0df2e76481d8b">vmaGetAllocationInfo</a>(allocator, m_Alloc, &allocInfo);</div><div class="line"> <span class="keywordflow">if</span>(allocInfo.<a class="code" href="struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67">deviceMemory</a> != VK_NULL_HANDLE)</div><div class="line"> {</div><div class="line"> <span class="comment">// It's all OK - safe to use m_Buf.</span></div><div class="line"> <span class="keywordflow">return</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Buffer not yet exists or lost - destroy and recreate it.</span></div><div class="line"></div><div class="line"> <a class="code" href="vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77">vmaDestroyBuffer</a>(allocator, m_Buf, m_Alloc);</div><div class="line"></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#accb8b06b1f677d858cb9af20705fa910">usage</a> = <a class="code" href="vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7">VMA_MEMORY_USAGE_GPU_ONLY</a>;</div><div class="line"> allocCreateInfo.<a class="code" href="struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b">flags</a> = <a class="code" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2">VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</a> |</div><div class="line"> <a class="code" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e">VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT</a>;</div><div class="line"></div><div class="line"> <a class="code" href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer</a>(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, <span class="keyword">nullptr</span>);</div><div class="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>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>
|
||||
|
@ -68,33 +68,8 @@ $(function() {
|
||||
<div class="contents">
|
||||
<div class="textblock"><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>On AMD GPUs on Windows, Vulkan memory from the type that has both <code>DEVICE_LOCAL</code> and <code>HOST_VISIBLE</code> flags should not be mapped for the time of any call to <code>vkQueueSubmit()</code> or <code>vkQueuePresent()</code>. Although legal, that would cause performance degradation because WDDM migrates such memory to system RAM. To ensure this, you can unmap all persistently mapped memory using just one function call. For details, see function <a class="el" href="vk__mem__alloc_8h.html#a26b87244491c1fe77f11fe9ab5779c27" title="Unmaps persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaUnmapPersistentlyMappedMemory()</a>, <a class="el" href="vk__mem__alloc_8h.html#a03366170bb8e186605518d2f5d65b85a" title="Maps back persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaMapPersistentlyMappedMemory()</a>. </p>
|
||||
<div class="fragment"><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_TRANSFER_SRC_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#accb8b06b1f677d858cb9af20705fa910">usage</a> = <a class="code" href="vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5">VMA_MEMORY_USAGE_CPU_ONLY</a>;</div><div class="line">allocCreateInfo.<a class="code" href="struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b">flags</a> = <a class="code" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ae443691ef3d077c0dc3de5576ac4c312">VMA_ALLOCATION_CREATE_PERSISTENT_MAP_BIT</a>;</div><div class="line"></div><div class="line">VkBuffer buf;</div><div class="line">VmaAllocation 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 class="line"></div><div class="line"><span class="comment">// Buffer is immediately mapped. You can access its memory.</span></div><div class="line">memcpy(allocInfo.<a class="code" href="struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2">pMappedData</a>, myData, 1024);</div></div><!-- fragment --><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>
|
||||
<div class="fragment"><div class="line">VkMemoryPropertyFlags memFlags;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca">vmaGetMemoryTypeProperties</a>(allocator, allocInfo.<a class="code" href="struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5">memoryType</a>, &memFlags);</div><div class="line"><span class="keywordflow">if</span>((memFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)</div><div class="line">{</div><div class="line"> VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };</div><div class="line"> memRange.memory = allocInfo.<a class="code" href="struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67">deviceMemory</a>;</div><div class="line"> memRange.offset = allocInfo.<a class="code" href="struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268">offset</a>;</div><div class="line"> memRange.size = allocInfo.<a class="code" href="struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f">size</a>;</div><div class="line"> vkFlushMappedMemoryRanges(device, 1, &memRange);</div><div class="line">}</div></div><!-- fragment --><p>On AMD GPUs on Windows, Vulkan memory from the type that has both <code>DEVICE_LOCAL</code> and <code>HOST_VISIBLE</code> flags should not be mapped for the time of any call to <code>vkQueueSubmit()</code> or <code>vkQueuePresent()</code>. Although legal, that would cause performance degradation because WDDM migrates such memory to system RAM. To ensure this, you can unmap all persistently mapped memory using just one function call. For details, see function <a class="el" href="vk__mem__alloc_8h.html#a26b87244491c1fe77f11fe9ab5779c27" title="Unmaps persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaUnmapPersistentlyMappedMemory()</a>, <a class="el" href="vk__mem__alloc_8h.html#a03366170bb8e186605518d2f5d65b85a" title="Maps back persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaMapPersistentlyMappedMemory()</a>. </p>
|
||||
</div></div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
|
@ -71,38 +71,19 @@ $(function() {
|
||||
<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>
|
||||
<div class="fragment"><div class="line"><span class="preprocessor">#define VMA_IMPLEMENTATION</span></div><div class="line"><span class="preprocessor">#include "vk_mem_alloc.h"</span></div></div><!-- fragment --><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="vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb" 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>
|
||||
<div class="fragment"><div class="line"><a class="code" href="struct_vma_allocator_create_info.html">VmaAllocatorCreateInfo</a> allocatorInfo = {};</div><div class="line">allocatorInfo.<a class="code" href="struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156">physicalDevice</a> = physicalDevice;</div><div class="line">allocatorInfo.<a class="code" href="struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500">device</a> = device;</div><div class="line"></div><div class="line">VmaAllocator allocator;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb">vmaCreateAllocator</a>(&allocatorInfo, &allocator);</div></div><!-- fragment --><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="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> 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 = 65536;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||
|
||||
VkBuffer buffer;
|
||||
VmaAllocation allocation;
|
||||
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &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> </div></div><!-- contents -->
|
||||
<div class="fragment"><div class="line">VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };</div><div class="line">bufferInfo.size = 65536;</div><div class="line">bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_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> allocInfo = {};</div><div class="line">allocInfo.<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>;</div><div class="line"></div><div class="line">VkBuffer buffer;</div><div class="line">VmaAllocation allocation;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer</a>(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, <span class="keyword">nullptr</span>);</div></div><!-- fragment --><p>Don't forget to destroy your objects when no longer needed:</p>
|
||||
<div class="fragment"><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77">vmaDestroyBuffer</a>(allocator, buffer, allocation);</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d">vmaDestroyAllocator</a>(allocator);</div></div><!-- fragment --> </div></div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
|
@ -1290,32 +1290,7 @@ Functions</h2></td></tr>
|
||||
<p>The function also frees empty <code>VkDeviceMemory</code> blocks.</p>
|
||||
<p>After allocation has been moved, its <a class="el" href="struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67" title="Handle to Vulkan memory object. ">VmaAllocationInfo::deviceMemory</a> and/or <a class="el" href="struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268" title="Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation. ">VmaAllocationInfo::offset</a> changes. You must query them again using <a class="el" href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b" title="Returns current information about specified allocation. ">vmaGetAllocationInfo()</a> if you need them.</p>
|
||||
<p>If an allocation has been moved, data in memory is copied to new place automatically, but if it was bound to a buffer or an image, you must destroy that object yourself, create new one and bind it to the new memory pointed by the allocation. You must use <code>vkDestroyBuffer()</code>, <code>vkDestroyImage()</code>, <code>vkCreateBuffer()</code>, <code>vkCreateImage()</code> for that purpose and NOT <a class="el" href="vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77" title="Destroys Vulkan buffer and frees allocated memory. ">vmaDestroyBuffer()</a>, <a class="el" href="vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e" title="Destroys Vulkan image and frees allocated memory. ">vmaDestroyImage()</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>! Example:</p>
|
||||
<pre class="fragment">VkDevice device = ...;
|
||||
VmaAllocator allocator = ...;
|
||||
std::vector<VkBuffer> buffers = ...;
|
||||
std::vector<VmaAllocation> allocations = ...;
|
||||
|
||||
std::vector<VkBool32> allocationsChanged(allocations.size());
|
||||
vmaDefragment(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), nullptr, nullptr);
|
||||
|
||||
for(size_t i = 0; i < allocations.size(); ++i)
|
||||
{
|
||||
if(allocationsChanged[i])
|
||||
{
|
||||
VmaAllocationInfo allocInfo;
|
||||
vmaGetAllocationInfo(allocator, allocations[i], &allocInfo);
|
||||
|
||||
vkDestroyBuffer(device, buffers[i], nullptr);
|
||||
|
||||
VkBufferCreateInfo bufferInfo = ...;
|
||||
vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]);
|
||||
|
||||
.// You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning.
|
||||
|
||||
vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset);
|
||||
}
|
||||
}
|
||||
</pre><p>This function may be time-consuming, so you shouldn't call it too often (like every frame or after every resource creation/destruction), but rater you can call it on special occasions (like when reloading a game level, when you just destroyed a lot of objects). </p>
|
||||
<div class="fragment"><div class="line">VkDevice device = ...;</div><div class="line">VmaAllocator allocator = ...;</div><div class="line">std::vector<VkBuffer> buffers = ...;</div><div class="line">std::vector<VmaAllocation> allocations = ...;</div><div class="line"></div><div class="line">std::vector<VkBool32> allocationsChanged(allocations.size());</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a6aced90fcc7b39882b6654a740a0b9bb">vmaDefragment</a>(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), <span class="keyword">nullptr</span>, <span class="keyword">nullptr</span>);</div><div class="line"></div><div class="line"><span class="keywordflow">for</span>(<span class="keywordtype">size_t</span> i = 0; i < allocations.size(); ++i)</div><div class="line">{</div><div class="line"> <span class="keywordflow">if</span>(allocationsChanged[i])</div><div class="line"> {</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#a86dd08aba8633bfa4ad0df2e76481d8b">vmaGetAllocationInfo</a>(allocator, allocations[i], &allocInfo);</div><div class="line"></div><div class="line"> vkDestroyBuffer(device, buffers[i], <span class="keyword">nullptr</span>);</div><div class="line"></div><div class="line"> VkBufferCreateInfo bufferInfo = ...;</div><div class="line"> vkCreateBuffer(device, &bufferInfo, <span class="keyword">nullptr</span>, &buffers[i]);</div><div class="line"> </div><div class="line"> <span class="comment">// You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning.</span></div><div class="line"> </div><div class="line"> vkBindBufferMemory(device, buffers[i], allocInfo.<a class="code" href="struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67">deviceMemory</a>, allocInfo.<a class="code" href="struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268">offset</a>);</div><div class="line"> }</div><div class="line">}</div></div><!-- fragment --><p>This function may be time-consuming, so you shouldn't call it too often (like every frame or after every resource creation/destruction), but rater you can call it on special occasions (like when reloading a game level, when you just destroyed a lot of objects). </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -1373,8 +1348,7 @@ for(size_t i = 0; i < allocations.size(); ++i)
|
||||
|
||||
<p>Destroys Vulkan buffer and frees allocated memory. </p>
|
||||
<p>This is just a convenience function equivalent to:</p>
|
||||
<pre class="fragment">vkDestroyBuffer(device, buffer, allocationCallbacks);
|
||||
vmaFreeMemory(allocator, allocation);</pre>
|
||||
<div class="fragment"><div class="line">vkDestroyBuffer(device, buffer, allocationCallbacks);</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568">vmaFreeMemory</a>(allocator, allocation);</div></div><!-- fragment -->
|
||||
</div>
|
||||
</div>
|
||||
<a id="ae50d2cb3b4a3bfd4dd40987234e50e7e"></a>
|
||||
@ -1411,8 +1385,7 @@ vmaFreeMemory(allocator, allocation);</pre>
|
||||
|
||||
<p>Destroys Vulkan image and frees allocated memory. </p>
|
||||
<p>This is just a convenience function equivalent to:</p>
|
||||
<pre class="fragment">vkDestroyImage(device, image, allocationCallbacks);
|
||||
vmaFreeMemory(allocator, allocation);</pre>
|
||||
<div class="fragment"><div class="line">vkDestroyImage(device, image, allocationCallbacks);</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568">vmaFreeMemory</a>(allocator, allocation);</div></div><!-- fragment -->
|
||||
</div>
|
||||
</div>
|
||||
<a id="a5485779c8f1948238fc4e92232fa65e1"></a>
|
||||
@ -1941,10 +1914,7 @@ vmaFreeMemory(allocator, allocation);</pre>
|
||||
|
||||
<p>Unmaps persistently mapped memory of types that are <code>HOST_COHERENT</code> and <code>DEVICE_LOCAL</code>. </p>
|
||||
<p>This is optional performance optimization. On AMD GPUs on Windows, Vulkan memory from the type that has both <code>DEVICE_LOCAL</code> and <code>HOST_VISIBLE</code> flags should not be mapped for the time of any call to <code>vkQueueSubmit()</code> or <code>vkQueuePresent()</code>. Although legal, that would cause performance degradation because WDDM migrates such memory to system RAM. To ensure this, you can unmap all persistently mapped memory using this function. Example:</p>
|
||||
<pre class="fragment">vmaUnmapPersistentlyMappedMemory(allocator);
|
||||
vkQueueSubmit(...)
|
||||
vmaMapPersistentlyMappedMemory(allocator);
|
||||
</pre><p>After this call <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> of some allocations may become null.</p>
|
||||
<div class="fragment"><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a26b87244491c1fe77f11fe9ab5779c27">vmaUnmapPersistentlyMappedMemory</a>(allocator);</div><div class="line">vkQueueSubmit(...)</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#a03366170bb8e186605518d2f5d65b85a">vmaMapPersistentlyMappedMemory</a>(allocator);</div></div><!-- fragment --><p>After this call <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> of some allocations may become null.</p>
|
||||
<p>This call is reference-counted. Memory is mapped again after you call <a class="el" href="vk__mem__alloc_8h.html#a03366170bb8e186605518d2f5d65b85a" title="Maps back persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaMapPersistentlyMappedMemory()</a> same number of times that you called <a class="el" href="vk__mem__alloc_8h.html#a26b87244491c1fe77f11fe9ab5779c27" title="Unmaps persistently mapped memory of types that are HOST_COHERENT and DEVICE_LOCAL. ">vmaUnmapPersistentlyMappedMemory()</a>. </p>
|
||||
|
||||
</div>
|
||||
|
File diff suppressed because one or more lines are too long
@ -64,9 +64,10 @@ In your project code:
|
||||
-# In exacly one C++ file define following macro before include to build library
|
||||
implementation.
|
||||
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "vk_mem_alloc.h"
|
||||
\code
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "vk_mem_alloc.h"
|
||||
\endcode
|
||||
|
||||
At program startup:
|
||||
|
||||
@ -74,13 +75,14 @@ At program startup:
|
||||
-# Fill VmaAllocatorCreateInfo structure and create `VmaAllocator` object by
|
||||
calling vmaCreateAllocator().
|
||||
|
||||
\code
|
||||
VmaAllocatorCreateInfo allocatorInfo = {};
|
||||
allocatorInfo.physicalDevice = physicalDevice;
|
||||
allocatorInfo.device = device;
|
||||
|
||||
VmaAllocatorCreateInfo allocatorInfo = {};
|
||||
allocatorInfo.physicalDevice = physicalDevice;
|
||||
allocatorInfo.device = device;
|
||||
|
||||
VmaAllocator allocator;
|
||||
vmaCreateAllocator(&allocatorInfo, &allocator);
|
||||
VmaAllocator allocator;
|
||||
vmaCreateAllocator(&allocatorInfo, &allocator);
|
||||
\endcode
|
||||
|
||||
When you want to create a buffer or image:
|
||||
|
||||
@ -89,23 +91,25 @@ When you want to create a buffer or image:
|
||||
-# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory
|
||||
already allocated and bound to it.
|
||||
|
||||
\code
|
||||
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufferInfo.size = 65536;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufferInfo.size = 65536;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||
|
||||
VkBuffer buffer;
|
||||
VmaAllocation allocation;
|
||||
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
|
||||
VkBuffer buffer;
|
||||
VmaAllocation allocation;
|
||||
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
|
||||
\endcode
|
||||
|
||||
Don't forget to destroy your objects when no longer needed:
|
||||
|
||||
|
||||
vmaDestroyBuffer(allocator, buffer, allocation);
|
||||
vmaDestroyAllocator(allocator);
|
||||
\code
|
||||
vmaDestroyBuffer(allocator, buffer, allocation);
|
||||
vmaDestroyAllocator(allocator);
|
||||
\endcode
|
||||
|
||||
\page persistently_mapped_memory Persistently mapped memory
|
||||
|
||||
@ -122,22 +126,23 @@ blocks that stay mapped all the time, so you can just access CPU pointer to it.
|
||||
VmaAllocationInfo::pMappedData pointer is already offseted to the beginning of
|
||||
particular allocation. Example:
|
||||
|
||||
\code
|
||||
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufCreateInfo.size = 1024;
|
||||
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
// Buffer is immediately mapped. You can access its memory.
|
||||
memcpy(allocInfo.pMappedData, myData, 1024);
|
||||
\endcode
|
||||
|
||||
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 `HOST_COHERENT` (here is surely is because
|
||||
@ -145,17 +150,18 @@ it's created with `VMA_MEMORY_USAGE_CPU_ONLY`), you should check it. If it's
|
||||
not, you should call `vkInvalidateMappedMemoryRanges()` before reading and
|
||||
`vkFlushMappedMemoryRanges()` after writing to mapped memory on CPU. Example:
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
\code
|
||||
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);
|
||||
}
|
||||
\endcode
|
||||
|
||||
On AMD GPUs on Windows, Vulkan memory from the type that has both `DEVICE_LOCAL`
|
||||
and `HOST_VISIBLE` flags should not be mapped for the time of any call to
|
||||
@ -185,34 +191,36 @@ To use custom memory pools:
|
||||
|
||||
Example:
|
||||
|
||||
\code
|
||||
// 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;
|
||||
|
||||
.// 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);
|
||||
|
||||
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;
|
||||
|
||||
.// 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;
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = {};
|
||||
allocCreateInfo.pool = pool;
|
||||
|
||||
VkBuffer buf;
|
||||
VmaAllocation alloc;
|
||||
VmaAllocationInfo allocInfo;
|
||||
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
|
||||
VkBuffer buf;
|
||||
VmaAllocation alloc;
|
||||
VmaAllocationInfo allocInfo;
|
||||
vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
|
||||
\endcode
|
||||
|
||||
You have to free all allocations made from this pool before destroying it.
|
||||
|
||||
|
||||
vmaDestroyBuffer(allocator, buf, alloc);
|
||||
vmaDestroyPool(allocator, pool);
|
||||
\code
|
||||
vmaDestroyBuffer(allocator, buf, alloc);
|
||||
vmaDestroyPool(allocator, pool);
|
||||
\endcode
|
||||
|
||||
\page defragmentation Defragmentation
|
||||
|
||||
@ -288,47 +296,48 @@ You need to call function vmaSetCurrentFrameIndex().
|
||||
|
||||
Example code:
|
||||
|
||||
\code
|
||||
struct MyBuffer
|
||||
{
|
||||
VkBuffer m_Buf = nullptr;
|
||||
VmaAllocation m_Alloc = nullptr;
|
||||
|
||||
struct MyBuffer
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
.// 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;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
\endcode
|
||||
|
||||
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
|
||||
@ -433,7 +442,6 @@ allocatorInfo.pVulkanFunctions = &vulkanFunctions;
|
||||
// Fill other members of allocatorInfo...
|
||||
\endcode
|
||||
|
||||
|
||||
3 . Use `VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT` flag when creating
|
||||
your `VmaAllocator` to inform the library that you enabled required extensions
|
||||
and you want the library to use them.
|
||||
@ -444,10 +452,19 @@ allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
|
||||
vmaCreateAllocator(&allocatorInfo, &allocator);
|
||||
\endcode
|
||||
|
||||
|
||||
That's all. The extension will be automatically used whenever you create a
|
||||
buffer using vmaCreateBuffer() or image using vmaCreateImage().
|
||||
|
||||
When using the extension together with Vulkan Validation Layer, you will receive
|
||||
warnings like this:
|
||||
|
||||
vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer.
|
||||
|
||||
It is OK, you should just ignore it. It happens because you use function
|
||||
`vkGetBufferMemoryRequirements2KHR()` instead of standard
|
||||
`vkGetBufferMemoryRequirements()`, while the validation layer seems to be
|
||||
unaware of it.
|
||||
|
||||
To learn more about this extension, see:
|
||||
|
||||
- [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VK_KHR_dedicated_allocation)
|
||||
@ -1144,10 +1161,11 @@ performance degradation because WDDM migrates such memory to system RAM.
|
||||
To ensure this, you can unmap all persistently mapped memory using this function.
|
||||
Example:
|
||||
|
||||
|
||||
vmaUnmapPersistentlyMappedMemory(allocator);
|
||||
vkQueueSubmit(...)
|
||||
vmaMapPersistentlyMappedMemory(allocator);
|
||||
\code
|
||||
vmaUnmapPersistentlyMappedMemory(allocator);
|
||||
vkQueueSubmit(...)
|
||||
vmaMapPersistentlyMappedMemory(allocator);
|
||||
\endcode
|
||||
|
||||
After this call VmaAllocationInfo::pMappedData of some allocations may become null.
|
||||
|
||||
@ -1230,32 +1248,33 @@ the allocation. You must use `vkDestroyBuffer()`, `vkDestroyImage()`,
|
||||
`vkCreateBuffer()`, `vkCreateImage()` for that purpose and NOT vmaDestroyBuffer(),
|
||||
vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage()! Example:
|
||||
|
||||
\code
|
||||
VkDevice device = ...;
|
||||
VmaAllocator allocator = ...;
|
||||
std::vector<VkBuffer> buffers = ...;
|
||||
std::vector<VmaAllocation> allocations = ...;
|
||||
|
||||
VkDevice device = ...;
|
||||
VmaAllocator allocator = ...;
|
||||
std::vector<VkBuffer> buffers = ...;
|
||||
std::vector<VmaAllocation> allocations = ...;
|
||||
std::vector<VkBool32> allocationsChanged(allocations.size());
|
||||
vmaDefragment(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), nullptr, nullptr);
|
||||
|
||||
std::vector<VkBool32> allocationsChanged(allocations.size());
|
||||
vmaDefragment(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), nullptr, nullptr);
|
||||
|
||||
for(size_t i = 0; i < allocations.size(); ++i)
|
||||
for(size_t i = 0; i < allocations.size(); ++i)
|
||||
{
|
||||
if(allocationsChanged[i])
|
||||
{
|
||||
if(allocationsChanged[i])
|
||||
{
|
||||
VmaAllocationInfo allocInfo;
|
||||
vmaGetAllocationInfo(allocator, allocations[i], &allocInfo);
|
||||
VmaAllocationInfo allocInfo;
|
||||
vmaGetAllocationInfo(allocator, allocations[i], &allocInfo);
|
||||
|
||||
vkDestroyBuffer(device, buffers[i], nullptr);
|
||||
vkDestroyBuffer(device, buffers[i], nullptr);
|
||||
|
||||
VkBufferCreateInfo bufferInfo = ...;
|
||||
vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]);
|
||||
VkBufferCreateInfo bufferInfo = ...;
|
||||
vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]);
|
||||
|
||||
.// You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning.
|
||||
// You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning.
|
||||
|
||||
vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset);
|
||||
}
|
||||
vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset);
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
|
||||
This function may be time-consuming, so you shouldn't call it too often (like
|
||||
every frame or after every resource creation/destruction), but rater you can
|
||||
@ -1300,9 +1319,10 @@ VkResult vmaCreateBuffer(
|
||||
|
||||
This is just a convenience function equivalent to:
|
||||
|
||||
|
||||
vkDestroyBuffer(device, buffer, allocationCallbacks);
|
||||
vmaFreeMemory(allocator, allocation);
|
||||
\code
|
||||
vkDestroyBuffer(device, buffer, allocationCallbacks);
|
||||
vmaFreeMemory(allocator, allocation);
|
||||
\endcode
|
||||
*/
|
||||
void vmaDestroyBuffer(
|
||||
VmaAllocator allocator,
|
||||
@ -1322,9 +1342,10 @@ VkResult vmaCreateImage(
|
||||
|
||||
This is just a convenience function equivalent to:
|
||||
|
||||
|
||||
vkDestroyImage(device, image, allocationCallbacks);
|
||||
vmaFreeMemory(allocator, allocation);
|
||||
\code
|
||||
vkDestroyImage(device, image, allocationCallbacks);
|
||||
vmaFreeMemory(allocator, allocation);
|
||||
\endcode
|
||||
*/
|
||||
void vmaDestroyImage(
|
||||
VmaAllocator allocator,
|
||||
|
Loading…
Reference in New Issue
Block a user