Merge branch 'master' into allocation_defragmentation_strategies

# Conflicts:
#	docs/html/vk__mem__alloc_8h_source.html
#	src/Tests.cpp
#	src/vk_mem_alloc.h
This commit is contained in:
Adam Sawicki 2018-11-16 14:36:57 +01:00
commit 48a12aa835
17 changed files with 692 additions and 16 deletions

View File

@ -20,7 +20,7 @@ Easy to integrate Vulkan memory allocation library.
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:
- It requires a lot of boilerplate code, just like everything else in Vulkan, because it is a low-level and high-performance API.
- There is additional level of indirection: `VkDeviceMemory` is allocated separately from creating `VkBuffer`/`VkImage` and they must be bound together. The binding cannot be changed later - resource must be recreated.
- There is additional level of indirection: `VkDeviceMemory` is allocated separately from creating `VkBuffer`/`VkImage` and they must be bound together.
- Driver must be queried for supported memory heaps and memory types. Different IHVs provide different types of it.
- It is recommended practice to allocate bigger chunks of memory and assign parts of them to particular resources.
@ -41,7 +41,7 @@ Additional features:
- Configuration: Fill optional members of CreateInfo structure to provide custom CPU memory allocator, pointers to Vulkan functions and other parameters.
- Customization: Predefine appropriate macros to provide your own implementation of all external facilities used by the library, from assert, mutex, and atomic, to vector and linked list.
- Support for memory mapping, reference-counted internally. Support for persistently mapped memory: Just allocate with appropriate flag and you get access to mapped pointer.
- Support for non-coherent memory. Functions that flush/invalidate memory. nonCoherentAtomSize is respected automatically.
- Support for non-coherent memory. Functions that flush/invalidate memory. `nonCoherentAtomSize` is respected automatically.
- Custom memory pools: Create a pool with desired parameters (e.g. fixed or limited maximum size) and allocate memory out of it.
- Linear allocator: Create a pool with linear algorithm and use it for much faster allocations and deallocations in free-at-once, stack, double stack, or ring buffer fashion.
- Support for VK_KHR_dedicated_allocation extension: Just enable it and it will be used automatically by the library.
@ -60,7 +60,7 @@ Additional features:
- Public interface in C, in same convention as Vulkan API. Implementation in C++.
- Error handling implemented by returning `VkResult` error codes - same way as in Vulkan.
- Interface documented using Doxygen-style comments.
- Platform-independent, but developed and tested on Windows using Visual Studio. Continuous integration setup for Windows and Linux. Tested also on Android and MacOS.
- Platform-independent, but developed and tested on Windows using Visual Studio. Continuous integration setup for Windows and Linux. Tested also on Android, MacOS, and other platforms.
# Example
@ -94,12 +94,16 @@ See **[Documentation](https://gpuopen-librariesandsdks.github.io/VulkanMemoryAll
# Software using this library
- **[Filament](https://github.com/google/filament)** - physically based rendering engine for Android, Windows, Linux and macOS, from Google. Apache License 2.0.
- **[Skia](https://github.com/google/skia)** - complete 2D graphic library for drawing Text, Geometries, and Images, from Google.
- **[PowerVR SDK](https://github.com/powervr-graphics/Native_SDK)** - C++ cross-platform 3D graphics SDK, from Imagination. License: MIT.
- **[Anvil](https://github.com/GPUOpen-LibrariesAndSDKs/Anvil)** - cross-platform framework for Vulkan. License: MIT.
- **[vkDOOM3](https://github.com/DustinHLand/vkDOOM3)** - Vulkan port of GPL DOOM 3 BFG Edition. License: GNU GPL.
- **[Lightweight Java Game Library (LWJGL)](https://www.lwjgl.org/)** - includes binding of the library for Java. License: BSD.
- **[The Forge](https://github.com/ConfettiFX/The-Forge)** - cross-platform rendering framework. Apache License 2.0.
- **[VK9](https://github.com/disks86/VK9)** - Direct3D 9 compatibility layer using Vulkan. Zlib lincese.
[Many other projects on GitHub](https://github.com/search?q=AMD_VULKAN_MEMORY_ALLOCATOR_H&type=Code) and some game development studios that use Vulkan in their games.
# See also
- **[Awesome Vulkan](https://github.com/vinjn/awesome-vulkan)** - a curated list of awesome Vulkan libraries, debuggers and resources.

View File

@ -23,7 +23,7 @@ Formats with only minor version incremented are backward compatible.
VmaReplay application supports all older versions.
Current version is:
1,3
1,4
# Configuration
@ -204,6 +204,11 @@ No parameters.
- pool : pointer
**vmaResizeAllocation** (min format version: 1.4)
- allocation : pointer
- newSize : uint64
# Data types
**bool**
@ -228,7 +233,7 @@ It should not contain end-of-line characters - results are then undefined.
# Example file
Vulkan Memory Allocator,Calls recording
1,3
1,4
Config,Begin
PhysicalDevice,apiVersion,4198477
PhysicalDevice,driverVersion,8388653

View File

@ -110,9 +110,12 @@ Allocation algorithm</h1>
Features not supported</h1>
<p>Features deliberately excluded from the scope of this library:</p>
<ul>
<li>Support for sparse binding and sparse residency. You can still use these features (when supported by the device) with VMA. You just need to do it yourself. Any explicit support for sparse binding/residency would rather require another, higher-level library on top of VMA.</li>
<li>Support for sparse binding and sparse residency. You can still use these features (when supported by the device) with VMA. You just need to do it yourself. Allocate memory pages with <a class="el" href="vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8" title="General purpose memory allocation. ">vmaAllocateMemory()</a>. Any explicit support for sparse binding/residency would rather require another, higher-level library on top of VMA.</li>
<li>Data transfer - issuing commands that transfer data between buffers or images, any usage of <code>VkCommandList</code> or <code>VkQueue</code> and related synchronization is responsibility of the user.</li>
<li>Allocations for imported/exported external memory. They tend to require explicit memory type index and dedicated allocation anyway, so they don't interact with main features of this library. Such special purpose allocations should be made manually, using <code>vkCreateBuffer()</code> and <code>vkAllocateMemory()</code>.</li>
<li>Recreation of buffers and images. Although the library has functions for buffer and image creation (<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>), you need to recreate these objects yourself after defragmentation. That's because the big structures <code>VkBufferCreateInfo</code>, <code>VkImageCreateInfo</code> are not stored in <a class="el" href="struct_vma_allocation.html" title="Represents single memory allocation. ">VmaAllocation</a> object.</li>
<li>Handling CPU memory allocation failures. When dynamically creating small C++ objects in CPU memory (not Vulkan memory), allocation failures are not checked and handled gracefully, because that would complicate code significantly and is usually not needed in desktop PC applications anyway.</li>
<li>Code free of any compiler warnings. Maintaining the library to compile and work correctly on so many different platforms is hard enough. Being free of any warnings, on any version of any compiler, is simply not feasible.</li>
<li>Support for any programming languages other than C/C++. Bindings to other languages are welcomed as external projects. </li>
</ul>
</div></div><!-- contents -->

View File

@ -366,6 +366,9 @@ $(function() {
<li>VmaRecordSettings
: <a class="el" href="vk__mem__alloc_8h.html#a0ab61e87ff6365f1d59915eadc37a9f0">vk_mem_alloc.h</a>
</li>
<li>vmaResizeAllocation()
: <a class="el" href="vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696">vk_mem_alloc.h</a>
</li>
<li>vmaSetAllocationUserData()
: <a class="el" href="vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f">vk_mem_alloc.h</a>
</li>

View File

@ -169,6 +169,9 @@ $(function() {
<li>vmaMapMemory()
: <a class="el" href="vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069">vk_mem_alloc.h</a>
</li>
<li>vmaResizeAllocation()
: <a class="el" href="vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696">vk_mem_alloc.h</a>
</li>
<li>vmaSetAllocationUserData()
: <a class="el" href="vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f">vk_mem_alloc.h</a>
</li>

View File

@ -82,6 +82,7 @@ Persistently mapped memory</h1>
<div class="fragment"><div class="line">VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };</div><div class="line">bufCreateInfo.size = <span class="keyword">sizeof</span>(ConstantBuffer);</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#ad9889c10c798b040d59c92f257cae597a11da372cc3a82931c5e5d6146cd9dd1f">VMA_ALLOCATION_CREATE_MAPPED_BIT</a>;</div><div class="line"></div><div class="line">VkBuffer buf;</div><div class="line"><a class="code" href="struct_vma_allocation.html">VmaAllocation</a> alloc;</div><div class="line"><a class="code" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> allocInfo;</div><div class="line"><a class="code" href="vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51">vmaCreateBuffer</a>(allocator, &amp;bufCreateInfo, &amp;allocCreateInfo, &amp;buf, &amp;alloc, &amp;allocInfo);</div><div class="line"></div><div class="line"><span class="comment">// Buffer is already 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>, &amp;constantBufferData, <span class="keyword">sizeof</span>(constantBufferData));</div></div><!-- fragment --><p>There are some exceptions though, when you should consider mapping memory only for a short period of time:</p>
<ul>
<li>When operating system is Windows 7 or 8.x (Windows 10 is not affected because it uses WDDM2), device is discrete AMD GPU, and memory type is the special 256 MiB pool of <code>DEVICE_LOCAL + HOST_VISIBLE</code> memory (selected when you use <a class="el" href="vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67">VMA_MEMORY_USAGE_CPU_TO_GPU</a>), then whenever a memory block allocated from this memory type stays mapped for the time of any call to <code>vkQueueSubmit()</code> or <code>vkQueuePresentKHR()</code>, this block is migrated by WDDM to system RAM, which degrades performance. It doesn't matter if that particular memory block is actually used by the command buffer being submitted.</li>
<li>On Mac/MoltenVK there is a known bug - <a href="https://github.com/KhronosGroup/MoltenVK/issues/175">Issue #175</a> which requires unmapping before GPU can see updated texture.</li>
<li>Keeping many large memory blocks mapped may impact performance or stability of some debugging tools.</li>
</ul>
<h1><a class="anchor" id="memory_mapping_cache_control"></a>

View File

@ -79,6 +79,7 @@ Project setup</h1>
<li>In exacly one CPP file define following macro before this include. It enables also internal definitions.</li>
</ol>
<div class="fragment"><div class="line"><span class="preprocessor">#define VMA_IMPLEMENTATION</span></div><div class="line"><span class="preprocessor">#include &quot;vk_mem_alloc.h&quot;</span></div></div><!-- fragment --><p>It may be a good idea to create dedicated CPP file just for this purpose.</p>
<p>Note on language: This library is written in C++, but has C-compatible interface. Thus you can include and use <a class="el" href="vk__mem__alloc_8h.html">vk_mem_alloc.h</a> in C or C++ code, but full implementation with <code>VMA_IMPLEMENTATION</code> macro must be compiled as C++, NOT as C.</p>
<p>Please note that this library includes header <code>&lt;vulkan/vulkan.h&gt;</code>, which in turn includes <code>&lt;windows.h&gt;</code> on Windows. If you need some specific macros defined before including these headers (like <code>WIN32_LEAN_AND_MEAN</code> or <code>WINVER</code> for Windows, <code>VK_USE_PLATFORM_WIN32_KHR</code> for Vulkan), you must define them before every <code>#include</code> of this library.</p>
<h1><a class="anchor" id="quick_start_initialization"></a>
Initialization</h1>

View File

@ -118,6 +118,7 @@ var searchData=
['vmarecordflagbits',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'VmaRecordFlagBits():&#160;vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#ade20b626a6635ce1bf30ea53dea774e4',1,'VmaRecordFlagBits():&#160;vk_mem_alloc.h']]],
['vmarecordflags',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]],
['vmarecordsettings',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'VmaRecordSettings'],['../vk__mem__alloc_8h.html#a0ab61e87ff6365f1d59915eadc37a9f0',1,'VmaRecordSettings():&#160;vk_mem_alloc.h']]],
['vmaresizeallocation',['vmaResizeAllocation',['../vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696',1,'vk_mem_alloc.h']]],
['vmasetallocationuserdata',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]],
['vmasetcurrentframeindex',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]],
['vmastatinfo',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../vk__mem__alloc_8h.html#a810b009a788ee8aac72a25b42ffbe31c',1,'VmaStatInfo():&#160;vk_mem_alloc.h']]],

View File

@ -35,6 +35,7 @@ var searchData=
['vmainvalidateallocation',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#a0d0eb0c1102268fa9a476d12ecbe4006',1,'vk_mem_alloc.h']]],
['vmamakepoolallocationslost',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]],
['vmamapmemory',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]],
['vmaresizeallocation',['vmaResizeAllocation',['../vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696',1,'vk_mem_alloc.h']]],
['vmasetallocationuserdata',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]],
['vmasetcurrentframeindex',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]],
['vmatouchallocation',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]],

View File

@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head><title></title>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta name="generator" content="Doxygen 1.8.14"/>
<link rel="stylesheet" type="text/css" href="search.css"/>
<script type="text/javascript" src="variables_c.js"></script>
<script type="text/javascript" src="search.js"></script>
</head>
<body class="SRPage">
<div id="SRIndex">
<div class="SRStatus" id="Loading">Loading...</div>
<div id="SRResults"></div>
<script type="text/javascript"><!--
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
createResults();
/* @license-end */
--></script>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
<script type="text/javascript"><!--
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
document.getElementById("Loading").style.display="none";
document.getElementById("NoMatches").style.display="none";
var searchResults = new SearchResults("searchResults");
searchResults.Search();
/* @license-end */
--></script>
</div>
</body>
</html>

View File

@ -0,0 +1,20 @@
var searchData=
[
['vkallocatememory',['vkAllocateMemory',['../struct_vma_vulkan_functions.html#a2943bf99dfd784a0e8f599d987e22e6c',1,'VmaVulkanFunctions']]],
['vkbindbuffermemory',['vkBindBufferMemory',['../struct_vma_vulkan_functions.html#a94fc4f3a605d9880bb3c0ba2c2fc80b2',1,'VmaVulkanFunctions']]],
['vkbindimagememory',['vkBindImageMemory',['../struct_vma_vulkan_functions.html#a1338d96a128a5ade648b8d934907c637',1,'VmaVulkanFunctions']]],
['vkcmdcopybuffer',['vkCmdCopyBuffer',['../struct_vma_vulkan_functions.html#ae5c0db8c89a3b82593dc16aa6a49fa3a',1,'VmaVulkanFunctions']]],
['vkcreatebuffer',['vkCreateBuffer',['../struct_vma_vulkan_functions.html#ae8084315a25006271a2edfc3a447519f',1,'VmaVulkanFunctions']]],
['vkcreateimage',['vkCreateImage',['../struct_vma_vulkan_functions.html#a23ebe70be515b9b5010a1d691200e325',1,'VmaVulkanFunctions']]],
['vkdestroybuffer',['vkDestroyBuffer',['../struct_vma_vulkan_functions.html#a7e054606faddb07f0e8556f3ed317d45',1,'VmaVulkanFunctions']]],
['vkdestroyimage',['vkDestroyImage',['../struct_vma_vulkan_functions.html#a90b898227039b1dcb3520f6e91f09ffa',1,'VmaVulkanFunctions']]],
['vkflushmappedmemoryranges',['vkFlushMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a33c322f4c4ad2810f8a9c97a277572f9',1,'VmaVulkanFunctions']]],
['vkfreememory',['vkFreeMemory',['../struct_vma_vulkan_functions.html#a4c658701778564d62034255b5dda91b4',1,'VmaVulkanFunctions']]],
['vkgetbuffermemoryrequirements',['vkGetBufferMemoryRequirements',['../struct_vma_vulkan_functions.html#a5b92901df89a4194b0d12f6071d4d143',1,'VmaVulkanFunctions']]],
['vkgetimagememoryrequirements',['vkGetImageMemoryRequirements',['../struct_vma_vulkan_functions.html#a475f6f49f8debe4d10800592606d53f4',1,'VmaVulkanFunctions']]],
['vkgetphysicaldevicememoryproperties',['vkGetPhysicalDeviceMemoryProperties',['../struct_vma_vulkan_functions.html#a60d25c33bba06bb8592e6875cbaa9830',1,'VmaVulkanFunctions']]],
['vkgetphysicaldeviceproperties',['vkGetPhysicalDeviceProperties',['../struct_vma_vulkan_functions.html#a77b7a74082823e865dd6546623468f96',1,'VmaVulkanFunctions']]],
['vkinvalidatemappedmemoryranges',['vkInvalidateMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a5c1093bc32386a8060c37c9f282078a1',1,'VmaVulkanFunctions']]],
['vkmapmemory',['vkMapMemory',['../struct_vma_vulkan_functions.html#ab5c1f38dea3a2cf00dc9eb4f57218c49',1,'VmaVulkanFunctions']]],
['vkunmapmemory',['vkUnmapMemory',['../struct_vma_vulkan_functions.html#acc798589736f0becb317fc2196c1d8b9',1,'VmaVulkanFunctions']]]
];

View File

@ -332,6 +332,9 @@ Functions</h2></td></tr>
<tr class="memitem:a11f0fbc034fa81a4efedd73d61ce7568"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a11f0fbc034fa81a4efedd73d61ce7568">vmaFreeMemory</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation)</td></tr>
<tr class="memdesc:a11f0fbc034fa81a4efedd73d61ce7568"><td class="mdescLeft">&#160;</td><td class="mdescRight">Frees memory previously allocated using <a class="el" href="vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8" title="General purpose memory allocation. ">vmaAllocateMemory()</a>, <a class="el" href="vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b">vmaAllocateMemoryForBuffer()</a>, or <a class="el" href="vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb" title="Function similar to vmaAllocateMemoryForBuffer(). ">vmaAllocateMemoryForImage()</a>. <a href="#a11f0fbc034fa81a4efedd73d61ce7568">More...</a><br /></td></tr>
<tr class="separator:a11f0fbc034fa81a4efedd73d61ce7568"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a0ff488958ca72b28e545880463cb8696"><td class="memItemLeft" align="right" valign="top">VkResult&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696">vmaResizeAllocation</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation, VkDeviceSize newSize)</td></tr>
<tr class="memdesc:a0ff488958ca72b28e545880463cb8696"><td class="mdescLeft">&#160;</td><td class="mdescRight">Tries to resize an allocation in place, if there is enough free memory after it. <a href="#a0ff488958ca72b28e545880463cb8696">More...</a><br /></td></tr>
<tr class="separator:a0ff488958ca72b28e545880463cb8696"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a86dd08aba8633bfa4ad0df2e76481d8b"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b">vmaGetAllocationInfo</a> (<a class="el" href="struct_vma_allocator.html">VmaAllocator</a> allocator, <a class="el" href="struct_vma_allocation.html">VmaAllocation</a> allocation, <a class="el" href="struct_vma_allocation_info.html">VmaAllocationInfo</a> *pAllocationInfo)</td></tr>
<tr class="memdesc:a86dd08aba8633bfa4ad0df2e76481d8b"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns current information about specified allocation and atomically marks it as used in current frame. <a href="#a86dd08aba8633bfa4ad0df2e76481d8b">More...</a><br /></td></tr>
<tr class="separator:a86dd08aba8633bfa4ad0df2e76481d8b"><td class="memSeparator" colspan="2">&#160;</td></tr>
@ -898,7 +901,8 @@ Functions</h2></td></tr>
</td></tr>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597ad242a04f802e25fef0b880afe8bb0a62"></a>VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that chooses biggest possible free range for the allocation. </p>
</td></tr>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777"></a>VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that chooses first suitable free range for the allocation. </p>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777"></a>VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that chooses first suitable free range for the allocation.</p>
<p>"First" doesn't necessarily means the one with smallest offset in memory, but rather the one that is easiest and fastest to find. </p>
</td></tr>
<tr><td class="fieldname"><a id="ad9889c10c798b040d59c92f257cae597a8af1210cf591784afa026d94998f735d"></a>VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT&#160;</td><td class="fielddoc"><p>Allocation strategy that tries to minimize memory usage. </p>
</td></tr>
@ -2559,6 +2563,50 @@ Functions</h2></td></tr>
<p>This function fails when used on allocation made in memory type that is not <code>HOST_VISIBLE</code>.</p>
<p>This function always fails when called for allocation that was created with <a class="el" href="vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2">VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT</a> flag. Such allocations cannot be mapped. </p>
</div>
</div>
<a id="a0ff488958ca72b28e545880463cb8696"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a0ff488958ca72b28e545880463cb8696">&#9670;&nbsp;</a></span>vmaResizeAllocation()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">VkResult vmaResizeAllocation </td>
<td>(</td>
<td class="paramtype"><a class="el" href="struct_vma_allocator.html">VmaAllocator</a>&#160;</td>
<td class="paramname"><em>allocator</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype"><a class="el" href="struct_vma_allocation.html">VmaAllocation</a>&#160;</td>
<td class="paramname"><em>allocation</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">VkDeviceSize&#160;</td>
<td class="paramname"><em>newSize</em>&#160;</td>
</tr>
<tr>
<td></td>
<td>)</td>
<td></td><td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Tries to resize an allocation in place, if there is enough free memory after it. </p>
<p>Tries to change allocation's size without moving or reallocating it. You can both shrink and grow allocation size. When growing, it succeeds only when the allocation belongs to a memory block with enough free space after it.</p>
<p>Returns <code>VK_SUCCESS</code> if allocation's size has been successfully changed. Returns <code>VK_ERROR_OUT_OF_POOL_MEMORY</code> if allocation's size could not be changed.</p>
<p>After successful call to this function, <a class="el" href="struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f" title="Size of this allocation, in bytes. ">VmaAllocationInfo::size</a> of this allocation changes. All other parameters stay the same: memory pool and type, alignment, offset, mapped pointer.</p>
<ul>
<li>Calling this function on allocation that is in lost state fails with result <code>VK_ERROR_VALIDATION_FAILED_EXT</code>.</li>
<li>Calling this function with <code>newSize</code> same as current allocation size does nothing and returns <code>VK_SUCCESS</code>.</li>
<li>Resizing dedicated allocations, as well as allocations created in pools that use linear or buddy algorithm, is not supported. The function returns <code>VK_ERROR_FEATURE_NOT_PRESENT</code> in such cases. Support may be added in the future. </li>
</ul>
</div>
</div>
<a id="af9147d31ffc11d62fc187bde283ed14f"></a>

View File

@ -1629,6 +1629,56 @@ static void TestUserData()
}
}
static void TestInvalidAllocations()
{
VkResult res;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
// Try to allocate 0 bytes.
{
VkMemoryRequirements memReq = {};
memReq.size = 0; // !!!
memReq.alignment = 4;
memReq.memoryTypeBits = UINT32_MAX;
VmaAllocation alloc = VK_NULL_HANDLE;
res = vmaAllocateMemory(g_hAllocator, &memReq, &allocCreateInfo, &alloc, nullptr);
TEST(res == VK_ERROR_VALIDATION_FAILED_EXT && alloc == VK_NULL_HANDLE);
}
// Try to create buffer with size = 0.
{
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufCreateInfo.size = 0; // !!!
VkBuffer buf = VK_NULL_HANDLE;
VmaAllocation alloc = VK_NULL_HANDLE;
res = vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, nullptr);
TEST(res == VK_ERROR_VALIDATION_FAILED_EXT && buf == VK_NULL_HANDLE && alloc == VK_NULL_HANDLE);
}
// Try to create image with one dimension = 0.
{
VkImageCreateInfo imageCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
imageCreateInfo.extent.width = 128;
imageCreateInfo.extent.height = 0; // !!!
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
VkImage image = VK_NULL_HANDLE;
VmaAllocation alloc = VK_NULL_HANDLE;
res = vmaCreateImage(g_hAllocator, &imageCreateInfo, &allocCreateInfo, &image, &alloc, nullptr);
TEST(res == VK_ERROR_VALIDATION_FAILED_EXT && image == VK_NULL_HANDLE && alloc == VK_NULL_HANDLE);
}
}
static void TestMemoryRequirements()
{
VkResult res;
@ -1733,6 +1783,8 @@ static void TestBasics()
}
TestUserData();
TestInvalidAllocations();
}
void TestHeapSizeLimit()
@ -3093,6 +3145,159 @@ static void TestPool_SameSize()
vmaDestroyPool(g_hAllocator, pool);
}
static void TestResize()
{
wprintf(L"Testing vmaResizeAllocation...\n");
const VkDeviceSize KILOBYTE = 1024ull;
const VkDeviceSize MEGABYTE = KILOBYTE * 1024;
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufCreateInfo.size = 2 * MEGABYTE;
bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
uint32_t memTypeIndex = UINT32_MAX;
TEST( vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &memTypeIndex) == VK_SUCCESS );
VmaPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
poolCreateInfo.blockSize = 8 * MEGABYTE;
poolCreateInfo.minBlockCount = 1;
poolCreateInfo.maxBlockCount = 1;
poolCreateInfo.memoryTypeIndex = memTypeIndex;
VmaPool pool;
TEST( vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS );
allocCreateInfo.pool = pool;
// Fill 8 MB pool with 4 * 2 MB allocations.
VmaAllocation allocs[4] = {};
VkMemoryRequirements memReq = {};
memReq.memoryTypeBits = UINT32_MAX;
memReq.alignment = 4;
memReq.size = bufCreateInfo.size;
VmaAllocationInfo allocInfo = {};
for(uint32_t i = 0; i < 4; ++i)
{
TEST( vmaAllocateMemory(g_hAllocator, &memReq, &allocCreateInfo, &allocs[i], nullptr) == VK_SUCCESS );
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 2MB
// Case: Resize to the same size always succeeds.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 2 * MEGABYTE) == VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
// Case: Shrink allocation at the end.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 1 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 1ull * 1024 * 1024);
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 1MB, free 1MB
// Case: Shrink allocation before free space.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 512 * KILOBYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 512 * KILOBYTE);
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 0.5MB, free 1.5MB
// Case: Shrink allocation before next allocation.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 1 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[0], &allocInfo);
TEST(allocInfo.size == 1 * MEGABYTE);
}
// Now it's: a0 1MB, free 1 MB, a1 2MB, a2 2MB, a3 0.5MB, free 1.5MB
// Case: Grow allocation while there is even more space available.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 1 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 1 * MEGABYTE);
}
// Now it's: a0 1MB, free 1 MB, a1 2MB, a2 2MB, a3 1MB, free 1MB
// Case: Grow allocation while there is exact amount of free space available.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 2 * MEGABYTE) == VK_SUCCESS );
vmaGetAllocationInfo(g_hAllocator, allocs[0], &allocInfo);
TEST(allocInfo.size == 2 * MEGABYTE);
}
// Now it's: a0 2MB, a1 2MB, a2 2MB, a3 1MB, free 1MB
// Case: Fail to grow when there is not enough free space due to next allocation.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[0], 3 * MEGABYTE) == VK_ERROR_OUT_OF_POOL_MEMORY );
vmaGetAllocationInfo(g_hAllocator, allocs[0], &allocInfo);
TEST(allocInfo.size == 2 * MEGABYTE);
}
// Case: Fail to grow when there is not enough free space due to end of memory block.
{
TEST( vmaResizeAllocation(g_hAllocator, allocs[3], 3 * MEGABYTE) == VK_ERROR_OUT_OF_POOL_MEMORY );
vmaGetAllocationInfo(g_hAllocator, allocs[3], &allocInfo);
TEST(allocInfo.size == 1 * MEGABYTE);
}
for(uint32_t i = 4; i--; )
{
vmaFreeMemory(g_hAllocator, allocs[i]);
}
vmaDestroyPool(g_hAllocator, pool);
// Test dedicated allocation
{
VmaAllocationCreateInfo dedicatedAllocCreateInfo = {};
dedicatedAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
dedicatedAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
VmaAllocation dedicatedAlloc = VK_NULL_HANDLE;
TEST( vmaAllocateMemory(g_hAllocator, &memReq, &dedicatedAllocCreateInfo, &dedicatedAlloc, nullptr) == VK_SUCCESS );
// Case: Resize to the same size always succeeds.
{
TEST( vmaResizeAllocation(g_hAllocator, dedicatedAlloc, 2 * MEGABYTE) == VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, dedicatedAlloc, &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
// Case: Shrinking fails.
{
TEST( vmaResizeAllocation(g_hAllocator, dedicatedAlloc, 1 * MEGABYTE) < VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, dedicatedAlloc, &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
// Case: Growing fails.
{
TEST( vmaResizeAllocation(g_hAllocator, dedicatedAlloc, 3 * MEGABYTE) < VK_SUCCESS);
vmaGetAllocationInfo(g_hAllocator, dedicatedAlloc, &allocInfo);
TEST(allocInfo.size == 2ull * 1024 * 1024);
}
vmaFreeMemory(g_hAllocator, dedicatedAlloc);
}
}
static bool ValidatePattern(const void* pMemory, size_t size, uint8_t pattern)
{
const uint8_t* pBytes = (const uint8_t*)pMemory;
@ -4707,6 +4912,7 @@ void Test()
#else
TestPool_SameSize();
TestHeapSizeLimit();
TestResize();
#endif
#if VMA_DEBUG_INITIALIZE_ALLOCATIONS
TestAllocationsInitialization();

View File

@ -83,6 +83,7 @@ enum class VMA_FUNCTION
TouchAllocation,
GetAllocationInfo,
MakePoolAllocationsLost,
ResizeAllocation,
Count
};
static const char* VMA_FUNCTION_NAMES[] = {
@ -105,6 +106,7 @@ static const char* VMA_FUNCTION_NAMES[] = {
"vmaTouchAllocation",
"vmaGetAllocationInfo",
"vmaMakePoolAllocationsLost",
"vmaResizeAllocation",
};
static_assert(
_countof(VMA_FUNCTION_NAMES) == (size_t)VMA_FUNCTION::Count,
@ -146,7 +148,7 @@ static size_t g_DefragmentAfterLineNextIndex = 0;
static bool ValidateFileVersion()
{
if(GetVersionMajor(g_FileVersion) == 1 &&
GetVersionMinor(g_FileVersion) <= 3)
GetVersionMinor(g_FileVersion) <= 4)
{
return true;
}
@ -1024,6 +1026,7 @@ private:
void ExecuteTouchAllocation(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteGetAllocationInfo(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteMakePoolAllocationsLost(size_t lineNumber, const CsvSplit& csvSplit);
void ExecuteResizeAllocation(size_t lineNumber, const CsvSplit& csvSplit);
void DestroyAllocation(size_t lineNumber, const CsvSplit& csvSplit);
@ -1168,6 +1171,8 @@ void Player::ExecuteLine(size_t lineNumber, const StrRange& line)
ExecuteGetAllocationInfo(lineNumber, csvSplit);
else if(StrRangeEq(functionName, "vmaMakePoolAllocationsLost"))
ExecuteMakePoolAllocationsLost(lineNumber, csvSplit);
else if(StrRangeEq(functionName, "vmaResizeAllocation"))
ExecuteResizeAllocation(lineNumber, csvSplit);
else
{
if(IssueWarning())
@ -2849,6 +2854,45 @@ void Player::ExecuteMakePoolAllocationsLost(size_t lineNumber, const CsvSplit& c
}
}
void Player::ExecuteResizeAllocation(size_t lineNumber, const CsvSplit& csvSplit)
{
m_Stats.RegisterFunctionCall(VMA_FUNCTION::ResizeAllocation);
if(ValidateFunctionParameterCount(lineNumber, csvSplit, 2, false))
{
uint64_t origPtr = 0;
uint64_t newSize = 0;
if(StrRangeToPtr(csvSplit.GetRange(FIRST_PARAM_INDEX), origPtr) &&
StrRangeToUint(csvSplit.GetRange(FIRST_PARAM_INDEX + 1), newSize))
{
if(origPtr != 0)
{
const auto it = m_Allocations.find(origPtr);
if(it != m_Allocations.end())
{
vmaResizeAllocation(m_Allocator, it->second.allocation, newSize);
UpdateMemStats();
}
else
{
if(IssueWarning())
{
printf("Line %zu: Allocation %llX not found.\n", lineNumber, origPtr);
}
}
}
}
else
{
if(IssueWarning())
{
printf("Line %zu: Invalid parameters for vmaResizeAllocation.\n", lineNumber);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Main functions

View File

@ -1306,6 +1306,15 @@ static void InitializeApplication()
allocatorInfo.pAllocationCallbacks = &cpuAllocationCallbacks;
}
// Uncomment to enable recording to CSV file.
/*
{
VmaRecordSettings recordSettings = {};
recordSettings.pFilePath = "VulkanSample.csv";
allocatorInfo.pRecordSettings = &recordSettings;
}
*/
ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
// Retrieve queue (doesn't need to be destroyed)

View File

@ -124,6 +124,10 @@ To do it properly:
It may be a good idea to create dedicated CPP file just for this purpose.
Note on language: This library is written in C++, but has C-compatible interface.
Thus you can include and use vk_mem_alloc.h in C or C++ code, but full
implementation with `VMA_IMPLEMENTATION` macro must be compiled as C++, NOT as C.
Please note that this library includes header `<vulkan/vulkan.h>`, which in turn
includes `<windows.h>` on Windows. If you need some specific macros defined
before including these headers (like `WIN32_LEAN_AND_MEAN` or
@ -388,6 +392,8 @@ There are some exceptions though, when you should consider mapping memory only f
block is migrated by WDDM to system RAM, which degrades performance. It doesn't
matter if that particular memory block is actually used by the command buffer
being submitted.
- On Mac/MoltenVK there is a known bug - [Issue #175](https://github.com/KhronosGroup/MoltenVK/issues/175)
which requires unmapping before GPU can see updated texture.
- Keeping many large memory blocks mapped may impact performance or stability of some debugging tools.
\section memory_mapping_cache_control Cache control
@ -1445,7 +1451,8 @@ Features deliberately excluded from the scope of this library:
- Support for sparse binding and sparse residency. You can still use these
features (when supported by the device) with VMA. You just need to do it
yourself. Any explicit support for sparse binding/residency would rather
yourself. Allocate memory pages with vmaAllocateMemory().
Any explicit support for sparse binding/residency would rather
require another, higher-level library on top of VMA.
- Data transfer - issuing commands that transfer data between buffers or images, any usage of
`VkCommandBuffer` or `VkQueue` and related synchronization is responsibility of the user.
@ -1453,6 +1460,18 @@ Features deliberately excluded from the scope of this library:
explicit memory type index and dedicated allocation anyway, so they don't
interact with main features of this library. Such special purpose allocations
should be made manually, using `vkCreateBuffer()` and `vkAllocateMemory()`.
- Recreation of buffers and images. Although the library has functions for
buffer and image creation (vmaCreateBuffer(), vmaCreateImage()), you need to
recreate these objects yourself after defragmentation. That's because the big
structures `VkBufferCreateInfo`, `VkImageCreateInfo` are not stored in
#VmaAllocation object.
- Handling CPU memory allocation failures. When dynamically creating small C++
objects in CPU memory (not Vulkan memory), allocation failures are not checked
and handled gracefully, because that would complicate code significantly and
is usually not needed in desktop PC applications anyway.
- Code free of any compiler warnings. Maintaining the library to compile and
work correctly on so many different platforms is hard enough. Being free of
any warnings, on any version of any compiler, is simply not feasible.
- Support for any programming languages other than C/C++.
Bindings to other languages are welcomed as external projects.
@ -1934,6 +1953,9 @@ typedef enum VmaAllocationCreateFlagBits {
VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT = 0x00020000,
/** Allocation strategy that chooses first suitable free range for the
allocation.
"First" doesn't necessarily means the one with smallest offset in memory,
but rather the one that is easiest and fastest to find.
*/
VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = 0x00040000,
@ -2359,6 +2381,31 @@ void vmaFreeMemory(
VmaAllocator allocator,
VmaAllocation allocation);
/** \brief Tries to resize an allocation in place, if there is enough free memory after it.
Tries to change allocation's size without moving or reallocating it.
You can both shrink and grow allocation size.
When growing, it succeeds only when the allocation belongs to a memory block with enough
free space after it.
Returns `VK_SUCCESS` if allocation's size has been successfully changed.
Returns `VK_ERROR_OUT_OF_POOL_MEMORY` if allocation's size could not be changed.
After successful call to this function, VmaAllocationInfo::size of this allocation changes.
All other parameters stay the same: memory pool and type, alignment, offset, mapped pointer.
- Calling this function on allocation that is in lost state fails with result `VK_ERROR_VALIDATION_FAILED_EXT`.
- Calling this function with `newSize` same as current allocation size does nothing and returns `VK_SUCCESS`.
- Resizing dedicated allocations, as well as allocations created in pools that use linear
or buddy algorithm, is not supported.
The function returns `VK_ERROR_FEATURE_NOT_PRESENT` in such cases.
Support may be added in the future.
*/
VkResult vmaResizeAllocation(
VmaAllocator allocator,
VmaAllocation allocation,
VkDeviceSize newSize);
/** \brief Returns current information about specified allocation and atomically marks it as used in current frame.
Current paramters of given allocation are returned in `pAllocationInfo`.
@ -2927,7 +2974,19 @@ remove them if not needed.
#define VMA_NULL nullptr
#endif
#if defined(__APPLE__) || defined(__ANDROID__)
#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
#include <cstdlib>
void *aligned_alloc(size_t alignment, size_t size)
{
// alignment must be >= sizeof(void*)
if(alignment < sizeof(void*))
{
alignment = sizeof(void*);
}
return memalign(alignment, size);
}
#elif defined(__APPLE__) || defined(__ANDROID__)
#include <cstdlib>
void *aligned_alloc(size_t alignment, size_t size)
{
@ -4681,6 +4740,8 @@ public:
VmaDeviceMemoryBlock* block,
VkDeviceSize offset);
void ChangeSize(VkDeviceSize newSize);
// pMappedData not null means allocation is created with MAPPED flag.
void InitDedicatedAllocation(
uint32_t memoryTypeIndex,
@ -4941,6 +5002,9 @@ public:
virtual void Free(const VmaAllocation allocation) = 0;
virtual void FreeAtOffset(VkDeviceSize offset) = 0;
// Tries to resize (grow or shrink) space for given allocation, in place.
virtual bool ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize) { return false; }
protected:
const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
@ -5020,6 +5084,8 @@ public:
virtual void Free(const VmaAllocation allocation);
virtual void FreeAtOffset(VkDeviceSize offset);
virtual bool ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize);
private:
uint32_t m_FreeCount;
VkDeviceSize m_SumFreeSize;
@ -5887,6 +5953,10 @@ public:
VmaAllocation allocation);
void RecordFreeMemory(uint32_t frameIndex,
VmaAllocation allocation);
void RecordResizeAllocation(
uint32_t frameIndex,
VmaAllocation allocation,
VkDeviceSize newSize);
void RecordSetAllocationUserData(uint32_t frameIndex,
VmaAllocation allocation,
const void* pUserData);
@ -6053,6 +6123,10 @@ public:
// Main deallocation function.
void FreeMemory(const VmaAllocation allocation);
VkResult ResizeAllocation(
const VmaAllocation alloc,
VkDeviceSize newSize);
void CalculateStats(VmaStats* pStats);
#if VMA_STATS_STRING_ENABLED
@ -6586,6 +6660,12 @@ void VmaAllocation_T::ChangeBlockAllocation(
m_BlockAllocation.m_Offset = offset;
}
void VmaAllocation_T::ChangeSize(VkDeviceSize newSize)
{
VMA_ASSERT(newSize > 0);
m_Size = newSize;
}
VkDeviceSize VmaAllocation_T::GetOffset() const
{
switch(m_Type)
@ -7512,6 +7592,133 @@ void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
VMA_ASSERT(0 && "Not found!");
}
bool VmaBlockMetadata_Generic::ResizeAllocation(const VmaAllocation alloc, VkDeviceSize newSize)
{
typedef VmaSuballocationList::iterator iter_type;
for(iter_type suballocItem = m_Suballocations.begin();
suballocItem != m_Suballocations.end();
++suballocItem)
{
VmaSuballocation& suballoc = *suballocItem;
if(suballoc.hAllocation == alloc)
{
iter_type nextItem = suballocItem;
++nextItem;
// Should have been ensured on higher level.
VMA_ASSERT(newSize != alloc->GetSize() && newSize > 0);
// Shrinking.
if(newSize < alloc->GetSize())
{
const VkDeviceSize sizeDiff = suballoc.size - newSize;
// There is next item.
if(nextItem != m_Suballocations.end())
{
// Next item is free.
if(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)
{
// Grow this next item backward.
UnregisterFreeSuballocation(nextItem);
nextItem->offset -= sizeDiff;
nextItem->size += sizeDiff;
RegisterFreeSuballocation(nextItem);
}
// Next item is not free.
else
{
// Create free item after current one.
VmaSuballocation newFreeSuballoc;
newFreeSuballoc.hAllocation = VK_NULL_HANDLE;
newFreeSuballoc.offset = suballoc.offset + newSize;
newFreeSuballoc.size = sizeDiff;
newFreeSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
iter_type newFreeSuballocIt = m_Suballocations.insert(nextItem, newFreeSuballoc);
RegisterFreeSuballocation(newFreeSuballocIt);
++m_FreeCount;
}
}
// This is the last item.
else
{
// Create free item at the end.
VmaSuballocation newFreeSuballoc;
newFreeSuballoc.hAllocation = VK_NULL_HANDLE;
newFreeSuballoc.offset = suballoc.offset + newSize;
newFreeSuballoc.size = sizeDiff;
newFreeSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
m_Suballocations.push_back(newFreeSuballoc);
iter_type newFreeSuballocIt = m_Suballocations.end();
RegisterFreeSuballocation(--newFreeSuballocIt);
++m_FreeCount;
}
suballoc.size = newSize;
m_SumFreeSize += sizeDiff;
}
// Growing.
else
{
const VkDeviceSize sizeDiff = newSize - suballoc.size;
// There is next item.
if(nextItem != m_Suballocations.end())
{
// Next item is free.
if(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)
{
// There is not enough free space, including margin.
if(nextItem->size < sizeDiff + VMA_DEBUG_MARGIN)
{
return false;
}
// There is more free space than required.
if(nextItem->size > sizeDiff)
{
// Move and shrink this next item.
UnregisterFreeSuballocation(nextItem);
nextItem->offset += sizeDiff;
nextItem->size -= sizeDiff;
RegisterFreeSuballocation(nextItem);
}
// There is exactly the amount of free space required.
else
{
// Remove this next free item.
UnregisterFreeSuballocation(nextItem);
m_Suballocations.erase(nextItem);
--m_FreeCount;
}
}
// Next item is not free - there is no space to grow.
else
{
return false;
}
}
// This is the last item - there is no space to grow.
else
{
return false;
}
suballoc.size = newSize;
m_SumFreeSize -= sizeDiff;
}
// We cannot call Validate() here because alloc object is updated to new size outside of this call.
return true;
}
}
VMA_ASSERT(0 && "Not found!");
return false;
}
bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
{
VkDeviceSize lastSize = 0;
@ -12041,7 +12248,7 @@ VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
// Write header.
fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
fprintf(m_File, "%s\n", "1,3");
fprintf(m_File, "%s\n", "1,4");
return VK_SUCCESS;
}
@ -12197,6 +12404,20 @@ void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
Flush();
}
void VmaRecorder::RecordResizeAllocation(
uint32_t frameIndex,
VmaAllocation allocation,
VkDeviceSize newSize)
{
CallParams callParams;
GetBasicParams(callParams);
VmaMutexLock lock(m_FileMutex, m_UseMutex);
fprintf(m_File, "%u,%.3f,%u,vmaResizeAllocation,%p,%llu\n", callParams.threadId, callParams.time, frameIndex,
allocation, newSize);
Flush();
}
void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
VmaAllocation allocation,
const void* pUserData)
@ -12998,6 +13219,10 @@ VkResult VmaAllocator_T::AllocateMemory(
{
VMA_ASSERT(VmaIsPow2(vkMemReq.alignment));
if(vkMemReq.size == 0)
{
return VK_ERROR_VALIDATION_FAILED_EXT;
}
if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
(createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
{
@ -13159,6 +13384,40 @@ void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
vma_delete(this, allocation);
}
VkResult VmaAllocator_T::ResizeAllocation(
const VmaAllocation alloc,
VkDeviceSize newSize)
{
if(newSize == 0 || alloc->GetLastUseFrameIndex() == VMA_FRAME_INDEX_LOST)
{
return VK_ERROR_VALIDATION_FAILED_EXT;
}
if(newSize == alloc->GetSize())
{
return VK_SUCCESS;
}
switch(alloc->GetType())
{
case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
return VK_ERROR_FEATURE_NOT_PRESENT;
case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
if(alloc->GetBlock()->m_pMetadata->ResizeAllocation(alloc, newSize))
{
alloc->ChangeSize(newSize);
VMA_HEAVY_ASSERT(alloc->GetBlock()->m_pMetadata->Validate());
return VK_SUCCESS;
}
else
{
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
default:
VMA_ASSERT(0);
return VK_ERROR_VALIDATION_FAILED_EXT;
}
}
void VmaAllocator_T::CalculateStats(VmaStats* pStats)
{
// Initialize.
@ -14477,6 +14736,30 @@ void vmaFreeMemory(
allocator->FreeMemory(allocation);
}
VkResult vmaResizeAllocation(
VmaAllocator allocator,
VmaAllocation allocation,
VkDeviceSize newSize)
{
VMA_ASSERT(allocator && allocation);
VMA_DEBUG_LOG("vmaResizeAllocation");
VMA_DEBUG_GLOBAL_MUTEX_LOCK
#if VMA_RECORDING_ENABLED
if(allocator->GetRecorder() != VMA_NULL)
{
allocator->GetRecorder()->RecordResizeAllocation(
allocator->GetCurrentFrameIndex(),
allocation,
newSize);
}
#endif
return allocator->ResizeAllocation(allocation, newSize);
}
void vmaGetAllocationInfo(
VmaAllocator allocator,
VmaAllocation allocation,
@ -14762,6 +15045,11 @@ VkResult vmaCreateBuffer(
{
VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
if(pBufferCreateInfo->size == 0)
{
return VK_ERROR_VALIDATION_FAILED_EXT;
}
VMA_DEBUG_LOG("vmaCreateBuffer");
VMA_DEBUG_GLOBAL_MUTEX_LOCK
@ -14900,6 +15188,15 @@ VkResult vmaCreateImage(
{
VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
if(pImageCreateInfo->extent.width == 0 ||
pImageCreateInfo->extent.height == 0 ||
pImageCreateInfo->extent.depth == 0 ||
pImageCreateInfo->mipLevels == 0 ||
pImageCreateInfo->arrayLayers == 0)
{
return VK_ERROR_VALIDATION_FAILED_EXT;
}
VMA_DEBUG_LOG("vmaCreateImage");
VMA_DEBUG_GLOBAL_MUTEX_LOCK

View File

@ -25,7 +25,7 @@ import json
from PIL import Image, ImageDraw, ImageFont
PROGRAM_VERSION = 'VMA Dump Visualization 1.0.0'
PROGRAM_VERSION = 'VMA Dump Visualization 2.0.0'
IMG_SIZE_X = 800
IMG_MARGIN = 8
FONT_SIZE = 10
@ -246,7 +246,7 @@ for iMemTypeIndex in sorted(data.keys()):
index = 0
for iPoolId, listPool in dictMemType['CustomPools'].items():
for objBlock in listPool:
if 'Algorithm' in objBlock:
if 'Algorithm' in objBlock and objBlock['Algorithm']:
sAlgorithm = ' (Algorithm: %s)' % (objBlock['Algorithm']);
else:
sAlgorithm = '';