mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-05 12:20:07 +00:00
Merge branch 'master' into sparse_binding_example
# Conflicts: # docs/html/vk__mem__alloc_8h.html # docs/html/vk__mem__alloc_8h_source.html # src/Tests.cpp # src/VulkanSample.cpp # src/vk_mem_alloc.h
This commit is contained in:
commit
6a6d8c6ea2
10
README.md
10
README.md
@ -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.
|
||||
|
@ -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
|
||||
@ -284,4 +289,4 @@ It should not contain end-of-line characters - results are then undefined.
|
||||
12552,0.695,0,vmaDestroyImage,000001D85B8B1620
|
||||
12552,0.695,0,vmaDestroyBuffer,000001D85B8B16C0
|
||||
12552,0.695,0,vmaDestroyBuffer,000001D85B8B1A80
|
||||
12552,0.695,0,vmaDestroyAllocator
|
||||
12552,0.695,0,vmaDestroyAllocator
|
||||
|
@ -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 -->
|
||||
|
@ -322,7 +322,7 @@ $(function() {
|
||||
: <a class="el" href="vk__mem__alloc_8h.html#ad63b2113c0bfdbeade1cb498f5a8580d">vk_mem_alloc.h</a>
|
||||
</li>
|
||||
<li>VmaPoolCreateFlagBits
|
||||
: <a class="el" href="vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7">vk_mem_alloc.h</a>
|
||||
: <a class="el" href="vk__mem__alloc_8h.html#a8f93195158e0e2ac80ca352064e71c1f">vk_mem_alloc.h</a>
|
||||
</li>
|
||||
<li>VmaPoolCreateFlags
|
||||
: <a class="el" href="vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a">vk_mem_alloc.h</a>
|
||||
@ -342,6 +342,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>
|
||||
|
@ -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>
|
||||
|
@ -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, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &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>, &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>
|
||||
|
@ -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 "vk_mem_alloc.h"</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><vulkan/vulkan.h></code>, which in turn includes <code><windows.h></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>
|
||||
|
@ -109,6 +109,7 @@ var searchData=
|
||||
['vmarecordflagbits',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'VmaRecordFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#ade20b626a6635ce1bf30ea53dea774e4',1,'VmaRecordFlagBits(): 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(): 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(): vk_mem_alloc.h']]],
|
||||
|
@ -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']]],
|
||||
|
30
docs/html/search/variables_c.html
Normal file
30
docs/html/search/variables_c.html
Normal 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&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&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>
|
20
docs/html/search/variables_c.js
Normal file
20
docs/html/search/variables_c.js
Normal 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']]]
|
||||
];
|
@ -216,7 +216,7 @@ Public Attributes</h2></td></tr>
|
||||
<li>If user tries to allocate more memory from that heap using this allocator, the allocation fails with <code>VK_ERROR_OUT_OF_DEVICE_MEMORY</code>.</li>
|
||||
<li>If the limit is smaller than heap size reported in <code>VkMemoryHeap::size</code>, the value of this limit will be reported instead when using <a class="el" href="vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19">vmaGetMemoryProperties()</a>.</li>
|
||||
</ul>
|
||||
<p>Warning! Using this feature may not be equivalent to installing a GPU with smaller amount of memory, because graphics driver doesn't necessary fail new allocations with <code>VK_ERROR_OUT_OF_DEVICE_MEMORY</code> result when memory capacity is exceeded. It may return success and just silently migrate some device memory blocks to system RAM. </p>
|
||||
<p>Warning! Using this feature may not be equivalent to installing a GPU with smaller amount of memory, because graphics driver doesn't necessary fail new allocations with <code>VK_ERROR_OUT_OF_DEVICE_MEMORY</code> result when memory capacity is exceeded. It may return success and just silently migrate some device memory blocks to system RAM. This driver behavior can also be controlled using VK_AMD_memory_overallocation_behavior extension. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
208
src/Tests.cpp
208
src/Tests.cpp
@ -1195,6 +1195,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;
|
||||
@ -1299,6 +1349,8 @@ static void TestBasics()
|
||||
}
|
||||
|
||||
TestUserData();
|
||||
|
||||
TestInvalidAllocations();
|
||||
}
|
||||
|
||||
void TestHeapSizeLimit()
|
||||
@ -2659,6 +2711,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;
|
||||
@ -4320,7 +4525,7 @@ void Test()
|
||||
// ########################################
|
||||
// ########################################
|
||||
|
||||
BasicTestBuddyAllocator();
|
||||
TestResize();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4332,6 +4537,7 @@ void Test()
|
||||
#else
|
||||
TestPool_SameSize();
|
||||
TestHeapSizeLimit();
|
||||
TestResize();
|
||||
#endif
|
||||
#if VMA_DEBUG_INITIALIZE_ALLOCATIONS
|
||||
TestAllocationsInitialization();
|
||||
|
@ -12,6 +12,11 @@ bool LineSplit::GetNextLine(StrRange& out)
|
||||
while(currLineEnd < m_NumBytes && m_Data[currLineEnd] != '\n')
|
||||
++currLineEnd;
|
||||
out.end = m_Data + currLineEnd;
|
||||
// Ignore trailing '\r' to support Windows end of line.
|
||||
if(out.end > out.beg && *(out.end - 1) == '\r')
|
||||
{
|
||||
--out.end;
|
||||
}
|
||||
m_NextLineBeg = currLineEnd + 1; // Past '\n'
|
||||
++m_NextLineIndex;
|
||||
return true;
|
||||
|
@ -82,6 +82,7 @@ enum class VMA_FUNCTION
|
||||
TouchAllocation,
|
||||
GetAllocationInfo,
|
||||
MakePoolAllocationsLost,
|
||||
ResizeAllocation,
|
||||
Count
|
||||
};
|
||||
static const char* VMA_FUNCTION_NAMES[] = {
|
||||
@ -104,6 +105,7 @@ static const char* VMA_FUNCTION_NAMES[] = {
|
||||
"vmaTouchAllocation",
|
||||
"vmaGetAllocationInfo",
|
||||
"vmaMakePoolAllocationsLost",
|
||||
"vmaResizeAllocation",
|
||||
};
|
||||
static_assert(
|
||||
_countof(VMA_FUNCTION_NAMES) == (size_t)VMA_FUNCTION::Count,
|
||||
@ -143,7 +145,7 @@ static size_t g_DumpStatsAfterLineNextIndex = 0;
|
||||
static bool ValidateFileVersion()
|
||||
{
|
||||
if(GetVersionMajor(g_FileVersion) == 1 &&
|
||||
GetVersionMinor(g_FileVersion) <= 3)
|
||||
GetVersionMinor(g_FileVersion) <= 4)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -1015,6 +1017,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);
|
||||
};
|
||||
@ -1156,6 +1159,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())
|
||||
@ -2599,6 +2604,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
|
||||
|
||||
|
@ -1345,6 +1345,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 queues (don't need to be destroyed).
|
||||
|
@ -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
|
||||
@ -387,7 +391,9 @@ There are some exceptions though, when you should consider mapping memory only f
|
||||
for the time of any call to `vkQueueSubmit()` or `vkQueuePresentKHR()`, 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.
|
||||
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
|
||||
@ -1444,7 +1450,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
|
||||
`VkCommandList` or `VkQueue` and related synchronization is responsibility of the user.
|
||||
@ -1452,6 +1459,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.
|
||||
|
||||
@ -1669,7 +1688,8 @@ typedef struct VmaAllocatorCreateInfo
|
||||
smaller amount of memory, because graphics driver doesn't necessary fail new
|
||||
allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is
|
||||
exceeded. It may return success and just silently migrate some device memory
|
||||
blocks to system RAM.
|
||||
blocks to system RAM. This driver behavior can also be controlled using
|
||||
VK_AMD_memory_overallocation_behavior extension.
|
||||
*/
|
||||
const VkDeviceSize* pHeapSizeLimit;
|
||||
/** \brief Pointers to Vulkan functions. Can be null if you leave define `VMA_STATIC_VULKAN_FUNCTIONS 1`.
|
||||
@ -1932,6 +1952,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,
|
||||
|
||||
@ -2402,6 +2425,31 @@ void vmaFreeMemoryPages(
|
||||
size_t allocationCount,
|
||||
VmaAllocation* pAllocations);
|
||||
|
||||
/** \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`.
|
||||
@ -2826,7 +2874,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)
|
||||
{
|
||||
@ -4520,7 +4580,9 @@ public:
|
||||
void ChangeBlockAllocation(
|
||||
VmaAllocator hAllocator,
|
||||
VmaDeviceMemoryBlock* block,
|
||||
VkDeviceSize offset);
|
||||
VkDeviceSize offset);
|
||||
|
||||
void ChangeSize(VkDeviceSize newSize);
|
||||
|
||||
// pMappedData not null means allocation is created with MAPPED flag.
|
||||
void InitDedicatedAllocation(
|
||||
@ -4782,6 +4844,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; }
|
||||
|
||||
@ -4861,6 +4926,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;
|
||||
@ -5623,6 +5690,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);
|
||||
@ -5792,6 +5863,10 @@ public:
|
||||
size_t allocationCount,
|
||||
const VmaAllocation* pAllocations);
|
||||
|
||||
VkResult ResizeAllocation(
|
||||
const VmaAllocation alloc,
|
||||
VkDeviceSize newSize);
|
||||
|
||||
void CalculateStats(VmaStats* pStats);
|
||||
|
||||
#if VMA_STATS_STRING_ENABLED
|
||||
@ -6338,6 +6413,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)
|
||||
@ -7264,6 +7345,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;
|
||||
@ -11453,7 +11661,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;
|
||||
}
|
||||
@ -11609,6 +11817,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)
|
||||
@ -12478,6 +12700,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)
|
||||
{
|
||||
@ -12652,6 +12878,40 @@ void VmaAllocator_T::FreeMemory(
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -12714,7 +12974,7 @@ VkResult VmaAllocator_T::Defragment(
|
||||
{
|
||||
if(pAllocationsChanged != VMA_NULL)
|
||||
{
|
||||
memset(pAllocationsChanged, 0, sizeof(*pAllocationsChanged));
|
||||
memset(pAllocationsChanged, 0, allocationCount * sizeof(VkBool32));
|
||||
}
|
||||
if(pDefragmentationStats != VMA_NULL)
|
||||
{
|
||||
@ -14145,6 +14405,30 @@ void vmaFreeMemoryPages(
|
||||
allocator->FreeMemory(allocationCount, pAllocations);
|
||||
}
|
||||
|
||||
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,
|
||||
@ -14376,6 +14660,11 @@ VkResult vmaCreateBuffer(
|
||||
VmaAllocationInfo* pAllocationInfo)
|
||||
{
|
||||
VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
|
||||
|
||||
if(pBufferCreateInfo->size == 0)
|
||||
{
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
|
||||
VMA_DEBUG_LOG("vmaCreateBuffer");
|
||||
|
||||
@ -14520,6 +14809,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
|
||||
|
@ -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 = '';
|
||||
|
Loading…
Reference in New Issue
Block a user