| // |
| // Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| // |
| |
| #ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H |
| #define AMD_VULKAN_MEMORY_ALLOCATOR_H |
| |
| /** \mainpage Vulkan Memory Allocator |
| |
| <b>Version 3.0.0-development</b> (2020-03-23) |
| |
| Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved. \n |
| License: MIT |
| |
| Documentation of all members: vk_mem_alloc.h |
| |
| \section main_table_of_contents Table of contents |
| |
| - <b>User guide</b> |
| - \subpage quick_start |
| - [Project setup](@ref quick_start_project_setup) |
| - [Initialization](@ref quick_start_initialization) |
| - [Resource allocation](@ref quick_start_resource_allocation) |
| - \subpage choosing_memory_type |
| - [Usage](@ref choosing_memory_type_usage) |
| - [Required and preferred flags](@ref choosing_memory_type_required_preferred_flags) |
| - [Explicit memory types](@ref choosing_memory_type_explicit_memory_types) |
| - [Custom memory pools](@ref choosing_memory_type_custom_memory_pools) |
| - [Dedicated allocations](@ref choosing_memory_type_dedicated_allocations) |
| - \subpage memory_mapping |
| - [Mapping functions](@ref memory_mapping_mapping_functions) |
| - [Persistently mapped memory](@ref memory_mapping_persistently_mapped_memory) |
| - [Cache flush and invalidate](@ref memory_mapping_cache_control) |
| - [Finding out if memory is mappable](@ref memory_mapping_finding_if_memory_mappable) |
| - \subpage staying_within_budget |
| - [Querying for budget](@ref staying_within_budget_querying_for_budget) |
| - [Controlling memory usage](@ref staying_within_budget_controlling_memory_usage) |
| - \subpage custom_memory_pools |
| - [Choosing memory type index](@ref custom_memory_pools_MemTypeIndex) |
| - [Linear allocation algorithm](@ref linear_algorithm) |
| - [Free-at-once](@ref linear_algorithm_free_at_once) |
| - [Stack](@ref linear_algorithm_stack) |
| - [Double stack](@ref linear_algorithm_double_stack) |
| - [Ring buffer](@ref linear_algorithm_ring_buffer) |
| - [Buddy allocation algorithm](@ref buddy_algorithm) |
| - \subpage defragmentation |
| - [Defragmenting CPU memory](@ref defragmentation_cpu) |
| - [Defragmenting GPU memory](@ref defragmentation_gpu) |
| - [Additional notes](@ref defragmentation_additional_notes) |
| - [Writing custom allocation algorithm](@ref defragmentation_custom_algorithm) |
| - \subpage lost_allocations |
| - \subpage statistics |
| - [Numeric statistics](@ref statistics_numeric_statistics) |
| - [JSON dump](@ref statistics_json_dump) |
| - \subpage allocation_annotation |
| - [Allocation user data](@ref allocation_user_data) |
| - [Allocation names](@ref allocation_names) |
| - \subpage debugging_memory_usage |
| - [Memory initialization](@ref debugging_memory_usage_initialization) |
| - [Margins](@ref debugging_memory_usage_margins) |
| - [Corruption detection](@ref debugging_memory_usage_corruption_detection) |
| - \subpage record_and_replay |
| - \subpage usage_patterns |
| - [Common mistakes](@ref usage_patterns_common_mistakes) |
| - [Simple patterns](@ref usage_patterns_simple) |
| - [Advanced patterns](@ref usage_patterns_advanced) |
| - \subpage configuration |
| - [Pointers to Vulkan functions](@ref config_Vulkan_functions) |
| - [Custom host memory allocator](@ref custom_memory_allocator) |
| - [Device memory allocation callbacks](@ref allocation_callbacks) |
| - [Device heap memory limit](@ref heap_memory_limit) |
| - \subpage vk_khr_dedicated_allocation |
| - \subpage enabling_buffer_device_address |
| - \subpage vk_amd_device_coherent_memory |
| - \subpage general_considerations |
| - [Thread safety](@ref general_considerations_thread_safety) |
| - [Validation layer warnings](@ref general_considerations_validation_layer_warnings) |
| - [Allocation algorithm](@ref general_considerations_allocation_algorithm) |
| - [Features not supported](@ref general_considerations_features_not_supported) |
| |
| \section main_see_also See also |
| |
| - [Product page on GPUOpen](https://gpuopen.com/gaming-product/vulkan-memory-allocator/) |
| - [Source repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) |
| |
| |
| |
| |
| \page quick_start Quick start |
| |
| \section quick_start_project_setup Project setup |
| |
| Vulkan Memory Allocator comes in form of a "stb-style" single header file. |
| You don't need to build it as a separate library project. |
| You can add this file directly to your project and submit it to code repository next to your other source files. |
| |
| "Single header" doesn't mean that everything is contained in C/C++ declarations, |
| like it tends to be in case of inline functions or C++ templates. |
| It means that implementation is bundled with interface in a single file and needs to be extracted using preprocessor macro. |
| If you don't do it properly, you will get linker errors. |
| |
| To do it properly: |
| |
| -# Include "vk_mem_alloc.h" file in each CPP file where you want to use the library. |
| This includes declarations of all members of the library. |
| -# In exacly one CPP file define following macro before this include. |
| It enables also internal definitions. |
| |
| \code |
| #define VMA_IMPLEMENTATION |
| #include "vk_mem_alloc.h" |
| \endcode |
| |
| 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 |
| `WINVER` for Windows, `VK_USE_PLATFORM_WIN32_KHR` for Vulkan), you must define |
| them before every `#include` of this library. |
| |
| |
| \section quick_start_initialization Initialization |
| |
| At program startup: |
| |
| -# Initialize Vulkan to have `VkPhysicalDevice`, `VkDevice` and `VkInstance` object. |
| -# Fill VmaAllocatorCreateInfo structure and create #VmaAllocator object by |
| calling vmaCreateAllocator(). |
| |
| \code |
| VmaAllocatorCreateInfo allocatorInfo = {}; |
| allocatorInfo.physicalDevice = physicalDevice; |
| allocatorInfo.device = device; |
| allocatorInfo.instance = instance; |
| |
| VmaAllocator allocator; |
| vmaCreateAllocator(&allocatorInfo, &allocator); |
| \endcode |
| |
| \section quick_start_resource_allocation Resource allocation |
| |
| When you want to create a buffer or image: |
| |
| -# Fill `VkBufferCreateInfo` / `VkImageCreateInfo` structure. |
| -# Fill VmaAllocationCreateInfo structure. |
| -# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory |
| already allocated and bound to it. |
| |
| \code |
| VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufferInfo.size = 65536; |
| bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| VmaAllocationCreateInfo allocInfo = {}; |
| allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| |
| VkBuffer buffer; |
| VmaAllocation allocation; |
| vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); |
| \endcode |
| |
| Don't forget to destroy your objects when no longer needed: |
| |
| \code |
| vmaDestroyBuffer(allocator, buffer, allocation); |
| vmaDestroyAllocator(allocator); |
| \endcode |
| |
| |
| \page choosing_memory_type Choosing memory type |
| |
| Physical devices in Vulkan support various combinations of memory heaps and |
| types. Help with choosing correct and optimal memory type for your specific |
| resource is one of the key features of this library. You can use it by filling |
| appropriate members of VmaAllocationCreateInfo structure, as described below. |
| You can also combine multiple methods. |
| |
| -# If you just want to find memory type index that meets your requirements, you |
| can use function: vmaFindMemoryTypeIndex(), vmaFindMemoryTypeIndexForBufferInfo(), |
| vmaFindMemoryTypeIndexForImageInfo(). |
| -# If you want to allocate a region of device memory without association with any |
| specific image or buffer, you can use function vmaAllocateMemory(). Usage of |
| this function is not recommended and usually not needed. |
| vmaAllocateMemoryPages() function is also provided for creating multiple allocations at once, |
| which may be useful for sparse binding. |
| -# If you already have a buffer or an image created, you want to allocate memory |
| for it and then you will bind it yourself, you can use function |
| vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(). |
| For binding you should use functions: vmaBindBufferMemory(), vmaBindImageMemory() |
| or their extended versions: vmaBindBufferMemory2(), vmaBindImageMemory2(). |
| -# If you want to create a buffer or an image, allocate memory for it and bind |
| them together, all in one call, you can use function vmaCreateBuffer(), |
| vmaCreateImage(). This is the easiest and recommended way to use this library. |
| |
| When using 3. or 4., the library internally queries Vulkan for memory types |
| supported for that buffer or image (function `vkGetBufferMemoryRequirements()`) |
| and uses only one of these types. |
| |
| If no memory type can be found that meets all the requirements, these functions |
| return `VK_ERROR_FEATURE_NOT_PRESENT`. |
| |
| You can leave VmaAllocationCreateInfo structure completely filled with zeros. |
| It means no requirements are specified for memory type. |
| It is valid, although not very useful. |
| |
| \section choosing_memory_type_usage Usage |
| |
| The easiest way to specify memory requirements is to fill member |
| VmaAllocationCreateInfo::usage using one of the values of enum #VmaMemoryUsage. |
| It defines high level, common usage types. |
| For more details, see description of this enum. |
| |
| For example, if you want to create a uniform buffer that will be filled using |
| transfer only once or infrequently and used for rendering every frame, you can |
| do it using following code: |
| |
| \code |
| VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufferInfo.size = 65536; |
| bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| VmaAllocationCreateInfo allocInfo = {}; |
| allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| |
| VkBuffer buffer; |
| VmaAllocation allocation; |
| vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); |
| \endcode |
| |
| \section choosing_memory_type_required_preferred_flags Required and preferred flags |
| |
| You can specify more detailed requirements by filling members |
| VmaAllocationCreateInfo::requiredFlags and VmaAllocationCreateInfo::preferredFlags |
| with a combination of bits from enum `VkMemoryPropertyFlags`. For example, |
| if you want to create a buffer that will be persistently mapped on host (so it |
| must be `HOST_VISIBLE`) and preferably will also be `HOST_COHERENT` and `HOST_CACHED`, |
| use following code: |
| |
| \code |
| VmaAllocationCreateInfo allocInfo = {}; |
| allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
| allocInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
| allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; |
| |
| VkBuffer buffer; |
| VmaAllocation allocation; |
| vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); |
| \endcode |
| |
| A memory type is chosen that has all the required flags and as many preferred |
| flags set as possible. |
| |
| If you use VmaAllocationCreateInfo::usage, it is just internally converted to |
| a set of required and preferred flags. |
| |
| \section choosing_memory_type_explicit_memory_types Explicit memory types |
| |
| If you inspected memory types available on the physical device and you have |
| a preference for memory types that you want to use, you can fill member |
| VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set |
| means that a memory type with that index is allowed to be used for the |
| allocation. Special value 0, just like `UINT32_MAX`, means there are no |
| restrictions to memory type index. |
| |
| Please note that this member is NOT just a memory type index. |
| Still you can use it to choose just one, specific memory type. |
| For example, if you already determined that your buffer should be created in |
| memory type 2, use following code: |
| |
| \code |
| uint32_t memoryTypeIndex = 2; |
| |
| VmaAllocationCreateInfo allocInfo = {}; |
| allocInfo.memoryTypeBits = 1u << memoryTypeIndex; |
| |
| VkBuffer buffer; |
| VmaAllocation allocation; |
| vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); |
| \endcode |
| |
| \section choosing_memory_type_custom_memory_pools Custom memory pools |
| |
| If you allocate from custom memory pool, all the ways of specifying memory |
| requirements described above are not applicable and the aforementioned members |
| of VmaAllocationCreateInfo structure are ignored. Memory type is selected |
| explicitly when creating the pool and then used to make all the allocations from |
| that pool. For further details, see \ref custom_memory_pools. |
| |
| \section choosing_memory_type_dedicated_allocations Dedicated allocations |
| |
| Memory for allocations is reserved out of larger block of `VkDeviceMemory` |
| allocated from Vulkan internally. That's the main feature of this whole library. |
| You can still request a separate memory block to be created for an allocation, |
| just like you would do in a trivial solution without using any allocator. |
| In that case, a buffer or image is always bound to that memory at offset 0. |
| This is called a "dedicated allocation". |
| You can explicitly request it by using flag #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. |
| The library can also internally decide to use dedicated allocation in some cases, e.g.: |
| |
| - When the size of the allocation is large. |
| - When [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension is enabled |
| and it reports that dedicated allocation is required or recommended for the resource. |
| - When allocation of next big memory block fails due to not enough device memory, |
| but allocation with the exact requested size succeeds. |
| |
| |
| \page memory_mapping Memory mapping |
| |
| To "map memory" in Vulkan means to obtain a CPU pointer to `VkDeviceMemory`, |
| to be able to read from it or write to it in CPU code. |
| Mapping is possible only of memory allocated from a memory type that has |
| `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. |
| Functions `vkMapMemory()`, `vkUnmapMemory()` are designed for this purpose. |
| You can use them directly with memory allocated by this library, |
| but it is not recommended because of following issue: |
| Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed. |
| This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan. |
| Because of this, Vulkan Memory Allocator provides following facilities: |
| |
| \section memory_mapping_mapping_functions Mapping functions |
| |
| The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory(). |
| They are safer and more convenient to use than standard Vulkan functions. |
| You can map an allocation multiple times simultaneously - mapping is reference-counted internally. |
| You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block. |
| The way it's implemented is that the library always maps entire memory block, not just region of the allocation. |
| For further details, see description of vmaMapMemory() function. |
| Example: |
| |
| \code |
| // Having these objects initialized: |
| |
| struct ConstantBuffer |
| { |
| ... |
| }; |
| ConstantBuffer constantBufferData; |
| |
| VmaAllocator allocator; |
| VkBuffer constantBuffer; |
| VmaAllocation constantBufferAllocation; |
| |
| // You can map and fill your buffer using following code: |
| |
| void* mappedData; |
| vmaMapMemory(allocator, constantBufferAllocation, &mappedData); |
| memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); |
| vmaUnmapMemory(allocator, constantBufferAllocation); |
| \endcode |
| |
| When mapping, you may see a warning from Vulkan validation layer similar to this one: |
| |
| <i>Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used.</i> |
| |
| It happens because the library maps entire `VkDeviceMemory` block, where different |
| types of images and buffers may end up together, especially on GPUs with unified memory like Intel. |
| You can safely ignore it if you are sure you access only memory of the intended |
| object that you wanted to map. |
| |
| |
| \section memory_mapping_persistently_mapped_memory Persistently mapped memory |
| |
| Kepping your memory persistently mapped is generally OK in Vulkan. |
| You don't need to unmap it before using its data on the GPU. |
| The library provides a special feature designed for that: |
| Allocations made with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag set in |
| VmaAllocationCreateInfo::flags stay mapped all the time, |
| so you can just access CPU pointer to it any time |
| without a need to call any "map" or "unmap" function. |
| Example: |
| |
| \code |
| VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufCreateInfo.size = sizeof(ConstantBuffer); |
| bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; |
| allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; |
| |
| VkBuffer buf; |
| VmaAllocation alloc; |
| VmaAllocationInfo allocInfo; |
| vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); |
| |
| // Buffer is already mapped. You can access its memory. |
| memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); |
| \endcode |
| |
| There are some exceptions though, when you should consider mapping memory only for a short period of time: |
| |
| - 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 `DEVICE_LOCAL + HOST_VISIBLE` memory |
| (selected when you use #VMA_MEMORY_USAGE_CPU_TO_GPU), |
| then whenever a memory block allocated from this memory type stays mapped |
| 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. |
| - 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 flush and invalidate |
| |
| Memory in Vulkan doesn't need to be unmapped before using it on GPU, |
| but unless a memory types has `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag set, |
| you need to manually **invalidate** cache before reading of mapped pointer |
| and **flush** cache after writing to mapped pointer. |
| Map/unmap operations don't do that automatically. |
| Vulkan provides following functions for this purpose `vkFlushMappedMemoryRanges()`, |
| `vkInvalidateMappedMemoryRanges()`, but this library provides more convenient |
| functions that refer to given allocation object: vmaFlushAllocation(), |
| vmaInvalidateAllocation(), |
| or multiple objects at once: vmaFlushAllocations(), vmaInvalidateAllocations(). |
| |
| Regions of memory specified for flush/invalidate must be aligned to |
| `VkPhysicalDeviceLimits::nonCoherentAtomSize`. This is automatically ensured by the library. |
| In any memory type that is `HOST_VISIBLE` but not `HOST_COHERENT`, all allocations |
| within blocks are aligned to this value, so their offsets are always multiply of |
| `nonCoherentAtomSize` and two different allocations never share same "line" of this size. |
| |
| Please note that memory allocated with #VMA_MEMORY_USAGE_CPU_ONLY is guaranteed to be `HOST_COHERENT`. |
| |
| Also, Windows drivers from all 3 **PC** GPU vendors (AMD, Intel, NVIDIA) |
| currently provide `HOST_COHERENT` flag on all memory types that are |
| `HOST_VISIBLE`, so on this platform you may not need to bother. |
| |
| \section memory_mapping_finding_if_memory_mappable Finding out if memory is mappable |
| |
| It may happen that your allocation ends up in memory that is `HOST_VISIBLE` (available for mapping) |
| despite it wasn't explicitly requested. |
| For example, application may work on integrated graphics with unified memory (like Intel) or |
| allocation from video memory might have failed, so the library chose system memory as fallback. |
| |
| You can detect this case and map such allocation to access its memory on CPU directly, |
| instead of launching a transfer operation. |
| In order to do that: inspect `allocInfo.memoryType`, call vmaGetMemoryTypeProperties(), |
| and look for `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag in properties of that memory type. |
| |
| \code |
| VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufCreateInfo.size = sizeof(ConstantBuffer); |
| bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| allocCreateInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
| |
| VkBuffer buf; |
| VmaAllocation alloc; |
| VmaAllocationInfo allocInfo; |
| vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); |
| |
| VkMemoryPropertyFlags memFlags; |
| vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags); |
| if((memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) |
| { |
| // Allocation ended up in mappable memory. You can map it and access it directly. |
| void* mappedData; |
| vmaMapMemory(allocator, alloc, &mappedData); |
| memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); |
| vmaUnmapMemory(allocator, alloc); |
| } |
| else |
| { |
| // Allocation ended up in non-mappable memory. |
| // You need to create CPU-side buffer in VMA_MEMORY_USAGE_CPU_ONLY and make a transfer. |
| } |
| \endcode |
| |
| You can even use #VMA_ALLOCATION_CREATE_MAPPED_BIT flag while creating allocations |
| that are not necessarily `HOST_VISIBLE` (e.g. using #VMA_MEMORY_USAGE_GPU_ONLY). |
| If the allocation ends up in memory type that is `HOST_VISIBLE`, it will be persistently mapped and you can use it directly. |
| If not, the flag is just ignored. |
| Example: |
| |
| \code |
| VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufCreateInfo.size = sizeof(ConstantBuffer); |
| bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; |
| |
| VkBuffer buf; |
| VmaAllocation alloc; |
| VmaAllocationInfo allocInfo; |
| vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); |
| |
| if(allocInfo.pUserData != nullptr) |
| { |
| // Allocation ended up in mappable memory. |
| // It's persistently mapped. You can access it directly. |
| memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); |
| } |
| else |
| { |
| // Allocation ended up in non-mappable memory. |
| // You need to create CPU-side buffer in VMA_MEMORY_USAGE_CPU_ONLY and make a transfer. |
| } |
| \endcode |
| |
| |
| \page staying_within_budget Staying within budget |
| |
| When developing a graphics-intensive game or program, it is important to avoid allocating |
| more GPU memory than it's physically available. When the memory is over-committed, |
| various bad things can happen, depending on the specific GPU, graphics driver, and |
| operating system: |
| |
| - It may just work without any problems. |
| - The application may slow down because some memory blocks are moved to system RAM |
| and the GPU has to access them through PCI Express bus. |
| - A new allocation may take very long time to complete, even few seconds, and possibly |
| freeze entire system. |
| - The new allocation may fail with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. |
| - It may even result in GPU crash (TDR), observed as `VK_ERROR_DEVICE_LOST` |
| returned somewhere later. |
| |
| \section staying_within_budget_querying_for_budget Querying for budget |
| |
| To query for current memory usage and available budget, use function vmaGetBudget(). |
| Returned structure #VmaBudget contains quantities expressed in bytes, per Vulkan memory heap. |
| |
| Please note that this function returns different information and works faster than |
| vmaCalculateStats(). vmaGetBudget() can be called every frame or even before every |
| allocation, while vmaCalculateStats() is intended to be used rarely, |
| only to obtain statistical information, e.g. for debugging purposes. |
| |
| It is recommended to use <b>VK_EXT_memory_budget</b> device extension to obtain information |
| about the budget from Vulkan device. VMA is able to use this extension automatically. |
| When not enabled, the allocator behaves same way, but then it estimates current usage |
| and available budget based on its internal information and Vulkan memory heap sizes, |
| which may be less precise. In order to use this extension: |
| |
| 1. Make sure extensions VK_EXT_memory_budget and VK_KHR_get_physical_device_properties2 |
| required by it are available and enable them. Please note that the first is a device |
| extension and the second is instance extension! |
| 2. Use flag #VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT when creating #VmaAllocator object. |
| 3. Make sure to call vmaSetCurrentFrameIndex() every frame. Budget is queried from |
| Vulkan inside of it to avoid overhead of querying it with every allocation. |
| |
| \section staying_within_budget_controlling_memory_usage Controlling memory usage |
| |
| There are many ways in which you can try to stay within the budget. |
| |
| First, when making new allocation requires allocating a new memory block, the library |
| tries not to exceed the budget automatically. If a block with default recommended size |
| (e.g. 256 MB) would go over budget, a smaller block is allocated, possibly even |
| dedicated memory for just this resource. |
| |
| If the size of the requested resource plus current memory usage is more than the |
| budget, by default the library still tries to create it, leaving it to the Vulkan |
| implementation whether the allocation succeeds or fails. You can change this behavior |
| by using #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag. With it, the allocation is |
| not made if it would exceed the budget or if the budget is already exceeded. |
| Some other allocations become lost instead to make room for it, if the mechanism of |
| [lost allocations](@ref lost_allocations) is used. |
| If that is not possible, the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. |
| Example usage pattern may be to pass the #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag |
| when creating resources that are not essential for the application (e.g. the texture |
| of a specific object) and not to pass it when creating critically important resources |
| (e.g. render targets). |
| |
| Finally, you can also use #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT flag to make sure |
| a new allocation is created only when it fits inside one of the existing memory blocks. |
| If it would require to allocate a new block, if fails instead with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. |
| This also ensures that the function call is very fast because it never goes to Vulkan |
| to obtain a new block. |
| |
| Please note that creating \ref custom_memory_pools with VmaPoolCreateInfo::minBlockCount |
| set to more than 0 will try to allocate memory blocks without checking whether they |
| fit within budget. |
| |
| |
| \page custom_memory_pools Custom memory pools |
| |
| A memory pool contains a number of `VkDeviceMemory` blocks. |
| The library automatically creates and manages default pool for each memory type available on the device. |
| Default memory pool automatically grows in size. |
| Size of allocated blocks is also variable and managed automatically. |
| |
| You can create custom pool and allocate memory out of it. |
| It can be useful if you want to: |
| |
| - Keep certain kind of allocations separate from others. |
| - Enforce particular, fixed size of Vulkan memory blocks. |
| - Limit maximum amount of Vulkan memory allocated for that pool. |
| - Reserve minimum or fixed amount of Vulkan memory always preallocated for that pool. |
| |
| To use custom memory pools: |
| |
| -# Fill VmaPoolCreateInfo structure. |
| -# Call vmaCreatePool() to obtain #VmaPool handle. |
| -# When making an allocation, set VmaAllocationCreateInfo::pool to this handle. |
| You don't need to specify any other parameters of this structure, like `usage`. |
| |
| Example: |
| |
| \code |
| // Create a pool that can have at most 2 blocks, 128 MiB each. |
| VmaPoolCreateInfo poolCreateInfo = {}; |
| poolCreateInfo.memoryTypeIndex = ... |
| poolCreateInfo.blockSize = 128ull * 1024 * 1024; |
| poolCreateInfo.maxBlockCount = 2; |
| |
| VmaPool pool; |
| vmaCreatePool(allocator, &poolCreateInfo, &pool); |
| |
| // Allocate a buffer out of it. |
| VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufCreateInfo.size = 1024; |
| bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.pool = pool; |
| |
| VkBuffer buf; |
| VmaAllocation alloc; |
| VmaAllocationInfo allocInfo; |
| vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); |
| \endcode |
| |
| You have to free all allocations made from this pool before destroying it. |
| |
| \code |
| vmaDestroyBuffer(allocator, buf, alloc); |
| vmaDestroyPool(allocator, pool); |
| \endcode |
| |
| \section custom_memory_pools_MemTypeIndex Choosing memory type index |
| |
| When creating a pool, you must explicitly specify memory type index. |
| To find the one suitable for your buffers or images, you can use helper functions |
| vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo(). |
| You need to provide structures with example parameters of buffers or images |
| that you are going to create in that pool. |
| |
| \code |
| VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| exampleBufCreateInfo.size = 1024; // Whatever. |
| exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; // Change if needed. |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; // Change if needed. |
| |
| uint32_t memTypeIndex; |
| vmaFindMemoryTypeIndexForBufferInfo(allocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex); |
| |
| VmaPoolCreateInfo poolCreateInfo = {}; |
| poolCreateInfo.memoryTypeIndex = memTypeIndex; |
| // ... |
| \endcode |
| |
| When creating buffers/images allocated in that pool, provide following parameters: |
| |
| - `VkBufferCreateInfo`: Prefer to pass same parameters as above. |
| Otherwise you risk creating resources in a memory type that is not suitable for them, which may result in undefined behavior. |
| Using different `VK_BUFFER_USAGE_` flags may work, but you shouldn't create images in a pool intended for buffers |
| or the other way around. |
| - VmaAllocationCreateInfo: You don't need to pass same parameters. Fill only `pool` member. |
| Other members are ignored anyway. |
| |
| \section linear_algorithm Linear allocation algorithm |
| |
| Each Vulkan memory block managed by this library has accompanying metadata that |
| keeps track of used and unused regions. By default, the metadata structure and |
| algorithm tries to find best place for new allocations among free regions to |
| optimize memory usage. This way you can allocate and free objects in any order. |
| |
|  |
| |
| Sometimes there is a need to use simpler, linear allocation algorithm. You can |
| create custom pool that uses such algorithm by adding flag |
| #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT to VmaPoolCreateInfo::flags while creating |
| #VmaPool object. Then an alternative metadata management is used. It always |
| creates new allocations after last one and doesn't reuse free regions after |
| allocations freed in the middle. It results in better allocation performance and |
| less memory consumed by metadata. |
| |
|  |
| |
| With this one flag, you can create a custom pool that can be used in many ways: |
| free-at-once, stack, double stack, and ring buffer. See below for details. |
| |
| \subsection linear_algorithm_free_at_once Free-at-once |
| |
| In a pool that uses linear algorithm, you still need to free all the allocations |
| individually, e.g. by using vmaFreeMemory() or vmaDestroyBuffer(). You can free |
| them in any order. New allocations are always made after last one - free space |
| in the middle is not reused. However, when you release all the allocation and |
| the pool becomes empty, allocation starts from the beginning again. This way you |
| can use linear algorithm to speed up creation of allocations that you are going |
| to release all at once. |
| |
|  |
| |
| This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount |
| value that allows multiple memory blocks. |
| |
| \subsection linear_algorithm_stack Stack |
| |
| When you free an allocation that was created last, its space can be reused. |
| Thanks to this, if you always release allocations in the order opposite to their |
| creation (LIFO - Last In First Out), you can achieve behavior of a stack. |
| |
|  |
| |
| This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount |
| value that allows multiple memory blocks. |
| |
| \subsection linear_algorithm_double_stack Double stack |
| |
| The space reserved by a custom pool with linear algorithm may be used by two |
| stacks: |
| |
| - First, default one, growing up from offset 0. |
| - Second, "upper" one, growing down from the end towards lower offsets. |
| |
| To make allocation from upper stack, add flag #VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT |
| to VmaAllocationCreateInfo::flags. |
| |
|  |
| |
| Double stack is available only in pools with one memory block - |
| VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. |
| |
| When the two stacks' ends meet so there is not enough space between them for a |
| new allocation, such allocation fails with usual |
| `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. |
| |
| \subsection linear_algorithm_ring_buffer Ring buffer |
| |
| When you free some allocations from the beginning and there is not enough free space |
| for a new one at the end of a pool, allocator's "cursor" wraps around to the |
| beginning and starts allocation there. Thanks to this, if you always release |
| allocations in the same order as you created them (FIFO - First In First Out), |
| you can achieve behavior of a ring buffer / queue. |
| |
|  |
| |
| Pools with linear algorithm support [lost allocations](@ref lost_allocations) when used as ring buffer. |
| If there is not enough free space for a new allocation, but existing allocations |
| from the front of the queue can become lost, they become lost and the allocation |
| succeeds. |
| |
|  |
| |
| Ring buffer is available only in pools with one memory block - |
| VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. |
| |
| \section buddy_algorithm Buddy allocation algorithm |
| |
| There is another allocation algorithm that can be used with custom pools, called |
| "buddy". Its internal data structure is based on a tree of blocks, each having |
| size that is a power of two and a half of its parent's size. When you want to |
| allocate memory of certain size, a free node in the tree is located. If it's too |
| large, it is recursively split into two halves (called "buddies"). However, if |
| requested allocation size is not a power of two, the size of a tree node is |
| aligned up to the nearest power of two and the remaining space is wasted. When |
| two buddy nodes become free, they are merged back into one larger node. |
| |
|  |
| |
| The advantage of buddy allocation algorithm over default algorithm is faster |
| allocation and deallocation, as well as smaller external fragmentation. The |
| disadvantage is more wasted space (internal fragmentation). |
| |
| For more information, please read ["Buddy memory allocation" on Wikipedia](https://en.wikipedia.org/wiki/Buddy_memory_allocation) |
| or other sources that describe this concept in general. |
| |
| To use buddy allocation algorithm with a custom pool, add flag |
| #VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT to VmaPoolCreateInfo::flags while creating |
| #VmaPool object. |
| |
| Several limitations apply to pools that use buddy algorithm: |
| |
| - It is recommended to use VmaPoolCreateInfo::blockSize that is a power of two. |
| Otherwise, only largest power of two smaller than the size is used for |
| allocations. The remaining space always stays unused. |
| - [Margins](@ref debugging_memory_usage_margins) and |
| [corruption detection](@ref debugging_memory_usage_corruption_detection) |
| don't work in such pools. |
| - [Lost allocations](@ref lost_allocations) don't work in such pools. You can |
| use them, but they never become lost. Support may be added in the future. |
| - [Defragmentation](@ref defragmentation) doesn't work with allocations made from |
| such pool. |
| |
| \page defragmentation Defragmentation |
| |
| Interleaved allocations and deallocations of many objects of varying size can |
| cause fragmentation over time, which can lead to a situation where the library is unable |
| to find a continuous range of free memory for a new allocation despite there is |
| enough free space, just scattered across many small free ranges between existing |
| allocations. |
| |
| To mitigate this problem, you can use defragmentation feature: |
| structure #VmaDefragmentationInfo2, function vmaDefragmentationBegin(), vmaDefragmentationEnd(). |
| Given set of allocations, |
| this function can move them to compact used memory, ensure more continuous free |
| space and possibly also free some `VkDeviceMemory` blocks. |
| |
| What the defragmentation does is: |
| |
| - Updates #VmaAllocation objects to point to new `VkDeviceMemory` and offset. |
| After allocation has been moved, its VmaAllocationInfo::deviceMemory and/or |
| VmaAllocationInfo::offset changes. You must query them again using |
| vmaGetAllocationInfo() if you need them. |
| - Moves actual data in memory. |
| |
| What it doesn't do, so you need to do it yourself: |
| |
| - Recreate buffers and images that were bound to allocations that were defragmented and |
| bind them with their new places in memory. |
| You must use `vkDestroyBuffer()`, `vkDestroyImage()`, |
| `vkCreateBuffer()`, `vkCreateImage()`, vmaBindBufferMemory(), vmaBindImageMemory() |
| for that purpose and NOT vmaDestroyBuffer(), |
| vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage(), because you don't need to |
| destroy or create allocation objects! |
| - Recreate views and update descriptors that point to these buffers and images. |
| |
| \section defragmentation_cpu Defragmenting CPU memory |
| |
| Following example demonstrates how you can run defragmentation on CPU. |
| Only allocations created in memory types that are `HOST_VISIBLE` can be defragmented. |
| Others are ignored. |
| |
| The way it works is: |
| |
| - It temporarily maps entire memory blocks when necessary. |
| - It moves data using `memmove()` function. |
| |
| \code |
| // Given following variables already initialized: |
| VkDevice device; |
| VmaAllocator allocator; |
| std::vector<VkBuffer> buffers; |
| std::vector<VmaAllocation> allocations; |
| |
| |
| const uint32_t allocCount = (uint32_t)allocations.size(); |
| std::vector<VkBool32> allocationsChanged(allocCount); |
| |
| VmaDefragmentationInfo2 defragInfo = {}; |
| defragInfo.allocationCount = allocCount; |
| defragInfo.pAllocations = allocations.data(); |
| defragInfo.pAllocationsChanged = allocationsChanged.data(); |
| defragInfo.maxCpuBytesToMove = VK_WHOLE_SIZE; // No limit. |
| defragInfo.maxCpuAllocationsToMove = UINT32_MAX; // No limit. |
| |
| VmaDefragmentationContext defragCtx; |
| vmaDefragmentationBegin(allocator, &defragInfo, nullptr, &defragCtx); |
| vmaDefragmentationEnd(allocator, defragCtx); |
| |
| for(uint32_t i = 0; i < allocCount; ++i) |
| { |
| if(allocationsChanged[i]) |
| { |
| // Destroy buffer that is immutably bound to memory region which is no longer valid. |
| vkDestroyBuffer(device, buffers[i], nullptr); |
| |
| // Create new buffer with same parameters. |
| VkBufferCreateInfo bufferInfo = ...; |
| vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]); |
| |
| // You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning. |
| |
| // Bind new buffer to new memory region. Data contained in it is already moved. |
| VmaAllocationInfo allocInfo; |
| vmaGetAllocationInfo(allocator, allocations[i], &allocInfo); |
| vmaBindBufferMemory(allocator, allocations[i], buffers[i]); |
| } |
| } |
| \endcode |
| |
| Setting VmaDefragmentationInfo2::pAllocationsChanged is optional. |
| This output array tells whether particular allocation in VmaDefragmentationInfo2::pAllocations at the same index |
| has been modified during defragmentation. |
| You can pass null, but you then need to query every allocation passed to defragmentation |
| for new parameters using vmaGetAllocationInfo() if you might need to recreate and rebind a buffer or image associated with it. |
| |
| If you use [Custom memory pools](@ref choosing_memory_type_custom_memory_pools), |
| you can fill VmaDefragmentationInfo2::poolCount and VmaDefragmentationInfo2::pPools |
| instead of VmaDefragmentationInfo2::allocationCount and VmaDefragmentationInfo2::pAllocations |
| to defragment all allocations in given pools. |
| You cannot use VmaDefragmentationInfo2::pAllocationsChanged in that case. |
| You can also combine both methods. |
| |
| \section defragmentation_gpu Defragmenting GPU memory |
| |
| It is also possible to defragment allocations created in memory types that are not `HOST_VISIBLE`. |
| To do that, you need to pass a command buffer that meets requirements as described in |
| VmaDefragmentationInfo2::commandBuffer. The way it works is: |
| |
| - It creates temporary buffers and binds them to entire memory blocks when necessary. |
| - It issues `vkCmdCopyBuffer()` to passed command buffer. |
| |
| Example: |
| |
| \code |
| // Given following variables already initialized: |
| VkDevice device; |
| VmaAllocator allocator; |
| VkCommandBuffer commandBuffer; |
| std::vector<VkBuffer> buffers; |
| std::vector<VmaAllocation> allocations; |
| |
| |
| const uint32_t allocCount = (uint32_t)allocations.size(); |
| std::vector<VkBool32> allocationsChanged(allocCount); |
| |
| VkCommandBufferBeginInfo cmdBufBeginInfo = ...; |
| vkBeginCommandBuffer(commandBuffer, &cmdBufBeginInfo); |
| |
| VmaDefragmentationInfo2 defragInfo = {}; |
| defragInfo.allocationCount = allocCount; |
| defragInfo.pAllocations = allocations.data(); |
| defragInfo.pAllocationsChanged = allocationsChanged.data(); |
| defragInfo.maxGpuBytesToMove = VK_WHOLE_SIZE; // Notice it's "GPU" this time. |
| defragInfo.maxGpuAllocationsToMove = UINT32_MAX; // Notice it's "GPU" this time. |
| defragInfo.commandBuffer = commandBuffer; |
| |
| VmaDefragmentationContext defragCtx; |
| vmaDefragmentationBegin(allocator, &defragInfo, nullptr, &defragCtx); |
| |
| vkEndCommandBuffer(commandBuffer); |
| |
| // Submit commandBuffer. |
| // Wait for a fence that ensures commandBuffer execution finished. |
| |
| vmaDefragmentationEnd(allocator, defragCtx); |
| |
| for(uint32_t i = 0; i < allocCount; ++i) |
| { |
| if(allocationsChanged[i]) |
| { |
| // Destroy buffer that is immutably bound to memory region which is no longer valid. |
| vkDestroyBuffer(device, buffers[i], nullptr); |
| |
| // Create new buffer with same parameters. |
| VkBufferCreateInfo bufferInfo = ...; |
| vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]); |
| |
| // You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning. |
| |
| // Bind new buffer to new memory region. Data contained in it is already moved. |
| VmaAllocationInfo allocInfo; |
| vmaGetAllocationInfo(allocator, allocations[i], &allocInfo); |
| vmaBindBufferMemory(allocator, allocations[i], buffers[i]); |
| } |
| } |
| \endcode |
| |
| You can combine these two methods by specifying non-zero `maxGpu*` as well as `maxCpu*` parameters. |
| The library automatically chooses best method to defragment each memory pool. |
| |
| You may try not to block your entire program to wait until defragmentation finishes, |
| but do it in the background, as long as you carefully fullfill requirements described |
| in function vmaDefragmentationBegin(). |
| |
| \section defragmentation_additional_notes Additional notes |
| |
| It is only legal to defragment allocations bound to: |
| |
| - buffers |
| - images created with `VK_IMAGE_CREATE_ALIAS_BIT`, `VK_IMAGE_TILING_LINEAR`, and |
| being currently in `VK_IMAGE_LAYOUT_GENERAL` or `VK_IMAGE_LAYOUT_PREINITIALIZED`. |
| |
| Defragmentation of images created with `VK_IMAGE_TILING_OPTIMAL` or in any other |
| layout may give undefined results. |
| |
| If you defragment allocations bound to images, new images to be bound to new |
| memory region after defragmentation should be created with `VK_IMAGE_LAYOUT_PREINITIALIZED` |
| and then transitioned to their original layout from before defragmentation if |
| needed using an image memory barrier. |
| |
| While using defragmentation, you may experience validation layer warnings, which you just need to ignore. |
| See [Validation layer warnings](@ref general_considerations_validation_layer_warnings). |
| |
| Please don't expect memory to be fully compacted after defragmentation. |
| Algorithms inside are based on some heuristics that try to maximize number of Vulkan |
| memory blocks to make totally empty to release them, as well as to maximimze continuous |
| empty space inside remaining blocks, while minimizing the number and size of allocations that |
| need to be moved. Some fragmentation may still remain - this is normal. |
| |
| \section defragmentation_custom_algorithm Writing custom defragmentation algorithm |
| |
| If you want to implement your own, custom defragmentation algorithm, |
| there is infrastructure prepared for that, |
| but it is not exposed through the library API - you need to hack its source code. |
| Here are steps needed to do this: |
| |
| -# Main thing you need to do is to define your own class derived from base abstract |
| class `VmaDefragmentationAlgorithm` and implement your version of its pure virtual methods. |
| See definition and comments of this class for details. |
| -# Your code needs to interact with device memory block metadata. |
| If you need more access to its data than it's provided by its public interface, |
| declare your new class as a friend class e.g. in class `VmaBlockMetadata_Generic`. |
| -# If you want to create a flag that would enable your algorithm or pass some additional |
| flags to configure it, add them to `VmaDefragmentationFlagBits` and use them in |
| VmaDefragmentationInfo2::flags. |
| -# Modify function `VmaBlockVectorDefragmentationContext::Begin` to create object |
| of your new class whenever needed. |
| |
| |
| \page lost_allocations Lost allocations |
| |
| If your game oversubscribes video memory, if may work OK in previous-generation |
| graphics APIs (DirectX 9, 10, 11, OpenGL) because resources are automatically |
| paged to system RAM. In Vulkan you can't do it because when you run out of |
| memory, an allocation just fails. If you have more data (e.g. textures) that can |
| fit into VRAM and you don't need it all at once, you may want to upload them to |
| GPU on demand and "push out" ones that are not used for a long time to make room |
| for the new ones, effectively using VRAM (or a cartain memory pool) as a form of |
| cache. Vulkan Memory Allocator can help you with that by supporting a concept of |
| "lost allocations". |
| |
| To create an allocation that can become lost, include #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT |
| flag in VmaAllocationCreateInfo::flags. Before using a buffer or image bound to |
| such allocation in every new frame, you need to query it if it's not lost. |
| To check it, call vmaTouchAllocation(). |
| If the allocation is lost, you should not use it or buffer/image bound to it. |
| You mustn't forget to destroy this allocation and this buffer/image. |
| vmaGetAllocationInfo() can also be used for checking status of the allocation. |
| Allocation is lost when returned VmaAllocationInfo::deviceMemory == `VK_NULL_HANDLE`. |
| |
| To create an allocation that can make some other allocations lost to make room |
| for it, use #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag. You will |
| usually use both flags #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT and |
| #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT at the same time. |
| |
| Warning! Current implementation uses quite naive, brute force algorithm, |
| which can make allocation calls that use #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT |
| flag quite slow. A new, more optimal algorithm and data structure to speed this |
| up is planned for the future. |
| |
| <b>Q: When interleaving creation of new allocations with usage of existing ones, |
| how do you make sure that an allocation won't become lost while it's used in the |
| current frame?</b> |
| |
| It is ensured because vmaTouchAllocation() / vmaGetAllocationInfo() not only returns allocation |
| status/parameters and checks whether it's not lost, but when it's not, it also |
| atomically marks it as used in the current frame, which makes it impossible to |
| become lost in that frame. It uses lockless algorithm, so it works fast and |
| doesn't involve locking any internal mutex. |
| |
| <b>Q: What if my allocation may still be in use by the GPU when it's rendering a |
| previous frame while I already submit new frame on the CPU?</b> |
| |
| You can make sure that allocations "touched" by vmaTouchAllocation() / vmaGetAllocationInfo() will not |
| become lost for a number of additional frames back from the current one by |
| specifying this number as VmaAllocatorCreateInfo::frameInUseCount (for default |
| memory pool) and VmaPoolCreateInfo::frameInUseCount (for custom pool). |
| |
| <b>Q: How do you inform the library when new frame starts?</b> |
| |
| You need to call function vmaSetCurrentFrameIndex(). |
| |
| Example code: |
| |
| \code |
| struct MyBuffer |
| { |
| VkBuffer m_Buf = nullptr; |
| VmaAllocation m_Alloc = nullptr; |
| |
| // Called when the buffer is really needed in the current frame. |
| void EnsureBuffer(); |
| }; |
| |
| void MyBuffer::EnsureBuffer() |
| { |
| // Buffer has been created. |
| if(m_Buf != VK_NULL_HANDLE) |
| { |
| // Check if its allocation is not lost + mark it as used in current frame. |
| if(vmaTouchAllocation(allocator, m_Alloc)) |
| { |
| // It's all OK - safe to use m_Buf. |
| return; |
| } |
| } |
| |
| // Buffer not yet exists or lost - destroy and recreate it. |
| |
| vmaDestroyBuffer(allocator, m_Buf, m_Alloc); |
| |
| VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| bufCreateInfo.size = 1024; |
| bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT | |
| VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT; |
| |
| vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, nullptr); |
| } |
| \endcode |
| |
| When using lost allocations, you may see some Vulkan validation layer warnings |
| about overlapping regions of memory bound to different kinds of buffers and |
| images. This is still valid as long as you implement proper handling of lost |
| allocations (like in the example above) and don't use them. |
| |
| You can create an allocation that is already in lost state from the beginning using function |
| vmaCreateLostAllocation(). It may be useful if you need a "dummy" allocation that is not null. |
| |
| You can call function vmaMakePoolAllocationsLost() to set all eligible allocations |
| in a specified custom pool to lost state. |
| Allocations that have been "touched" in current frame or VmaPoolCreateInfo::frameInUseCount frames back |
| cannot become lost. |
| |
| <b>Q: Can I touch allocation that cannot become lost?</b> |
| |
| Yes, although it has no visible effect. |
| Calls to vmaGetAllocationInfo() and vmaTouchAllocation() update last use frame index |
| also for allocations that cannot become lost, but the only way to observe it is to dump |
| internal allocator state using vmaBuildStatsString(). |
| You can use this feature for debugging purposes to explicitly mark allocations that you use |
| in current frame and then analyze JSON dump to see for how long each allocation stays unused. |
| |
| |
| \page statistics Statistics |
| |
| This library contains functions that return information about its internal state, |
| especially the amount of memory allocated from Vulkan. |
| Please keep in mind that these functions need to traverse all internal data structures |
| to gather these information, so they may be quite time-consuming. |
| Don't call them too often. |
| |
| \section statistics_numeric_statistics Numeric statistics |
| |
| You can query for overall statistics of the allocator using function vmaCalculateStats(). |
| Information are returned using structure #VmaStats. |
| It contains #VmaStatInfo - number of allocated blocks, number of allocations |
| (occupied ranges in these blocks), number of unused (free) ranges in these blocks, |
| number of bytes used and unused (but still allocated from Vulkan) and other information. |
| They are summed across memory heaps, memory types and total for whole allocator. |
| |
| You can query for statistics of a custom pool using function vmaGetPoolStats(). |
| Information are returned using structure #VmaPoolStats. |
| |
| You can query for information about specific allocation using function vmaGetAllocationInfo(). |
| It fill structure #VmaAllocationInfo. |
| |
| \section statistics_json_dump JSON dump |
| |
| You can dump internal state of the allocator to a string in JSON format using function vmaBuildStatsString(). |
| The result is guaranteed to be correct JSON. |
| It uses ANSI encoding. |
| Any strings provided by user (see [Allocation names](@ref allocation_names)) |
| are copied as-is and properly escaped for JSON, so if they use UTF-8, ISO-8859-2 or any other encoding, |
| this JSON string can be treated as using this encoding. |
| It must be freed using function vmaFreeStatsString(). |
| |
| The format of this JSON string is not part of official documentation of the library, |
| but it will not change in backward-incompatible way without increasing library major version number |
| and appropriate mention in changelog. |
| |
| The JSON string contains all the data that can be obtained using vmaCalculateStats(). |
| It can also contain detailed map of allocated memory blocks and their regions - |
| free and occupied by allocations. |
| This allows e.g. to visualize the memory or assess fragmentation. |
| |
| |
| \page allocation_annotation Allocation names and user data |
| |
| \section allocation_user_data Allocation user data |
| |
| You can annotate allocations with your own information, e.g. for debugging purposes. |
| To do that, fill VmaAllocationCreateInfo::pUserData field when creating |
| an allocation. It's an opaque `void*` pointer. You can use it e.g. as a pointer, |
| some handle, index, key, ordinal number or any other value that would associate |
| the allocation with your custom metadata. |
| |
| \code |
| VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| // Fill bufferInfo... |
| |
| MyBufferMetadata* pMetadata = CreateBufferMetadata(); |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| allocCreateInfo.pUserData = pMetadata; |
| |
| VkBuffer buffer; |
| VmaAllocation allocation; |
| vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, nullptr); |
| \endcode |
| |
| The pointer may be later retrieved as VmaAllocationInfo::pUserData: |
| |
| \code |
| VmaAllocationInfo allocInfo; |
| vmaGetAllocationInfo(allocator, allocation, &allocInfo); |
| MyBufferMetadata* pMetadata = (MyBufferMetadata*)allocInfo.pUserData; |
| \endcode |
| |
| It can also be changed using function vmaSetAllocationUserData(). |
| |
| Values of (non-zero) allocations' `pUserData` are printed in JSON report created by |
| vmaBuildStatsString(), in hexadecimal form. |
| |
| \section allocation_names Allocation names |
| |
| There is alternative mode available where `pUserData` pointer is used to point to |
| a null-terminated string, giving a name to the allocation. To use this mode, |
| set #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT flag in VmaAllocationCreateInfo::flags. |
| Then `pUserData` passed as VmaAllocationCreateInfo::pUserData or argument to |
| vmaSetAllocationUserData() must be either null or pointer to a null-terminated string. |
| The library creates internal copy of the string, so the pointer you pass doesn't need |
| to be valid for whole lifetime of the allocation. You can free it after the call. |
| |
| \code |
| VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; |
| // Fill imageInfo... |
| |
| std::string imageName = "Texture: "; |
| imageName += fileName; |
| |
| VmaAllocationCreateInfo allocCreateInfo = {}; |
| allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| allocCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT; |
| allocCreateInfo.pUserData = imageName.c_str(); |
| |
| VkImage image; |
| VmaAllocation allocation; |
| vmaCreateImage(allocator, &imageInfo, &allocCreateInfo, &image, &allocation, nullptr); |
| \endcode |
| |
| The value of `pUserData` pointer of the allocation will be different than the one |
| you passed when setting allocation's name - pointing to a buffer managed |
| internally that holds copy of the string. |
| |
| \code |
| VmaAllocationInfo allocInfo; |
| vmaGetAllocationInfo(allocator, allocation, &allocInfo); |
| const char* imageName = (const char*)allocInfo.pUserData; |
| printf("Image name: %s\n", imageName); |
| \endcode |
| |
| That string is also printed in JSON report created by vmaBuildStatsString(). |
| |
| \note Passing string name to VMA allocation doesn't automatically set it to the Vulkan buffer or image created with it. |
| You must do it manually using an extension like VK_EXT_debug_utils, which is independent of this library. |
| |
| |
| \page debugging_memory_usage Debugging incorrect memory usage |
| |
| If you suspect a bug with memory usage, like usage of uninitialized memory or |
| memory being overwritten out of bounds of an allocation, |
| you can use debug features of this library to verify this. |
| |
| \section debugging_memory_usage_initialization Memory initialization |
| |
| If you experience a bug with incorrect and nondeterministic data in your program and you suspect uninitialized memory to be used, |
| you can enable automatic memory initialization to verify this. |
| To do it, define macro `VMA_DEBUG_INITIALIZE_ALLOCATIONS` to 1. |
| |
| \code |
| #define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1 |
| #include "vk_mem_alloc.h" |
| \endcode |
| |
| It makes memory of all new allocations initialized to bit pattern `0xDCDCDCDC`. |
| Before an allocation is destroyed, its memory is filled with bit pattern `0xEFEFEFEF`. |
| Memory is automatically mapped and unmapped if necessary. |
| |
| If you find these values while debugging your program, good chances are that you incorrectly |
| read Vulkan memory that is allocated but not initialized, or already freed, respectively. |
| |
| Memory initialization works only with memory types that are `HOST_VISIBLE`. |
| It works also with dedicated allocations. |
| It doesn't work with allocations created with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, |
| as they cannot be mapped. |
| |
| \section debugging_memory_usage_margins Margins |
| |
| By default, allocations are laid out in memory blocks next to each other if possible |
| (considering required alignment, `bufferImageGranularity`, and `nonCoherentAtomSize`). |
| |
|  |
| |
| Define macro `VMA_DEBUG_MARGIN` to some non-zero value (e.g. 16) to enforce specified |
| number of bytes as a margin before and after every allocation. |
| |
| \code |
| #define VMA_DEBUG_MARGIN 16 |
| #include "vk_mem_alloc.h" |
| \endcode |
| |
|  |
| |
| If your bug goes away after enabling margins, it means it may be caused by memory |
| being overwritten outside of allocation boundaries. It is not 100% certain though. |
| Change in application behavior may also be caused by different order and distribution |
| of allocations across memory blocks after margins are applied. |
| |
| The margin is applied also before first and after last allocation in a block. |
| It may occur only once between two adjacent allocations. |
| |
| Margins work with all types of memory. |
| |
| Margin is applied only to allocations made out of memory blocks and not to dedicated |
| allocations, which have their own memory block of specific size. |
| It is thus not applied to allocations made using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT flag |
| or those automatically decided to put into dedicated allocations, e.g. due to its |
| large size or recommended by VK_KHR_dedicated_allocation extension. |
| Margins are also not active in custom pools created with #VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT flag. |
| |
| Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space. |
| |
| Note that enabling margins increases memory usage and fragmentation. |
| |
| \section debugging_memory_usage_corruption_detection Corruption detection |
| |
| You can additionally define macro `VMA_DEBUG_DETECT_CORRUPTION` to 1 to enable validation |
| of contents of the margins. |
| |
| \code |
| #define VMA_DEBUG_MARGIN 16 |
| #define VMA_DEBUG_DETECT_CORRUPTION 1 |
| #include "vk_mem_alloc.h" |
| \endcode |
| |
| When this feature is enabled, number of bytes specified as `VMA_DEBUG_MARGIN` |
| (it must be multiply of 4) before and after every allocation is filled with a magic number. |
| This idea is also know as "canary". |
| Memory is automatically mapped and unmapped if necessary. |
| |
| This number is validated automatically when the allocation is destroyed. |
| If it's not equal to the expected value, `VMA_ASSERT()` is executed. |
| It clearly means that either CPU or GPU overwritten the memory outside of boundaries of the allocation, |
| which indicates a serious bug. |
| |
| You can also explicitly request checking margins of all allocations in all memory blocks |
| that belong to specified memory types by using function vmaCheckCorruption(), |
| or in memory blocks that belong to specified custom pool, by using function |
| vmaCheckPoolCorruption(). |
| |
| Margin validation (corruption detection) works only for memory types that are |
| `HOST_VISIBLE` and `HOST_COHERENT`. |
| |
| |
| \page record_and_replay Record and replay |
| |
| \section record_and_replay_introduction Introduction |
| |
| While using the library, sequence of calls to its functions together with their |
| parameters can be recorded to a file and later replayed using standalone player |
| application. It can be useful to: |
| |
| - Test correctness - check if same sequence of calls will not cause crash or |
| failures on a target platform. |
| - Gather statistics - see number of allocations, peak memory usage, number of |
| calls etc. |
| - Benchmark performance - see how much time it takes to replay the whole |
| sequence. |
| |
| \section record_and_replay_usage Usage |
| |
| Recording functionality is disabled by default. |
| To enable it, define following macro before every include of this library: |
| |
| \code |
| #define VMA_RECORDING_ENABLED 1 |
| \endcode |
| |
| <b>To record sequence of calls to a file:</b> Fill in |
| VmaAllocatorCreateInfo::pRecordSettings member while creating #VmaAllocator |
| object. File is opened and written during whole lifetime of the allocator. |
| |
| <b>To replay file:</b> Use VmaReplay - standalone command-line program. |
| Precompiled binary can be found in "bin" directory. |
| Its source can be found in "src/VmaReplay" directory. |
| Its project is generated by Premake. |
| Command line syntax is printed when the program is launched without parameters. |
| Basic usage: |
| |
| VmaReplay.exe MyRecording.csv |
| |
| <b>Documentation of file format</b> can be found in file: "docs/Recording file format.md". |
| It's a human-readable, text file in CSV format (Comma Separated Values). |
| |
| \section record_and_replay_additional_considerations Additional considerations |
| |
| - Replaying file that was recorded on a different GPU (with different parameters |
| like `bufferImageGranularity`, `nonCoherentAtomSize`, and especially different |
| set of memory heaps and types) may give different performance and memory usage |
| results, as well as issue some warnings and errors. |
| - Current implementation of recording in VMA, as well as VmaReplay application, is |
| coded and tested only on Windows. Inclusion of recording code is driven by |
| `VMA_RECORDING_ENABLED` macro. Support for other platforms should be easy to |
| add. Contributions are welcomed. |
| |
| |
| \page usage_patterns Recommended usage patterns |
| |
| See also slides from talk: |
| [Sawicki, Adam. Advanced Graphics Techniques Tutorial: Memory management in Vulkan and DX12. Game Developers Conference, 2018](https://www.gdcvault.com/play/1025458/Advanced-Graphics-Techniques-Tutorial-New) |
| |
| |
| \section usage_patterns_common_mistakes Common mistakes |
| |
| <b>Use of CPU_TO_GPU instead of CPU_ONLY memory</b> |
| |
| #VMA_MEMORY_USAGE_CPU_TO_GPU is recommended only for resources that will be |
| mapped and written by the CPU, as well as read directly by the GPU - like some |
| buffers or textures updated every frame (dynamic). If you create a staging copy |
| of a resource to be written by CPU and then used as a source of transfer to |
| another resource placed in the GPU memory, that staging resource should be |
| created with #VMA_MEMORY_USAGE_CPU_ONLY. Please read the descriptions of these |
| enums carefully for details. |
| |
| <b>Unnecessary use of custom pools</b> |
| |
| \ref custom_memory_pools may be useful for special purposes - when you want to |
| keep certain type of resources separate e.g. to reserve minimum amount of memory |
| for them, limit maximum amount of memory they can occupy, or make some of them |
| push out the other through the mechanism of \ref lost_allocations. For most |
| resources this is not needed and so it is not recommended to create #VmaPool |
| objects and allocations out of them. Allocating from the default pool is sufficient. |
| |
| \section usage_patterns_simple Simple patterns |
| |
| \subsection usage_patterns_simple_render_targets Render targets |
| |
| <b>When:</b> |
| Any resources that you frequently write and read on GPU, |
| e.g. images used as color attachments (aka "render targets"), depth-stencil attachments, |
| images/buffers used as storage image/buffer (aka "Unordered Access View (UAV)"). |
| |
| <b>What to do:</b> |
| Create them in video memory that is fastest to access from GPU using |
| #VMA_MEMORY_USAGE_GPU_ONLY. |
| |
| Consider using [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension |
| and/or manually creating them as dedicated allocations using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, |
| especially if they are large or if you plan to destroy and recreate them e.g. when |
| display resolution changes. |
| Prefer to create such resources first and all other GPU resources (like textures and vertex buffers) later. |
| |
| \subsection usage_patterns_simple_immutable_resources Immutable resources |
| |
| <b>When:</b> |
| Any resources that you fill on CPU only once (aka "immutable") or infrequently |
| and then read frequently on GPU, |
| e.g. textures, vertex and index buffers, constant buffers that don't change often. |
| |
| <b>What to do:</b> |
| Create them in video memory that is fastest to access from GPU using |
| #VMA_MEMORY_USAGE_GPU_ONLY. |
| |
| To initialize content of such resource, create a CPU-side (aka "staging") copy of it |
| in system memory - #VMA_MEMORY_USAGE_CPU_ONLY, map it, fill it, |
| and submit a transfer from it to the GPU resource. |
| You can keep the staging copy if you need it for another upload transfer in the future. |
| If you don't, you can destroy it or reuse this buffer for uploading different resource |
| after the transfer finishes. |
| |
| Prefer to create just buffers in system memory rather than images, even for uploading textures. |
| Use `vkCmdCopyBufferToImage()`. |
| Dont use images with `VK_IMAGE_TILING_LINEAR`. |
| |
| \subsection usage_patterns_dynamic_resources Dynamic resources |
| |
| <b>When:</b> |
| Any resources that change frequently (aka "dynamic"), e.g. every frame or every draw call, |
| written on CPU, read on GPU. |
| |
| <b>What to do:</b> |
| Create them using #VMA_MEMORY_USAGE_CPU_TO_GPU. |
| You can map it and write to it directly on CPU, as well as read from it on GPU. |
| |
| This is a more complex situation. Different solutions are possible, |
| and the best one depends on specific GPU type, but you can use this simple approach for the start. |
| Prefer to write to such resource sequentially (e.g. using `memcpy`). |
| Don't perform random access or any reads from it on CPU, as it may be very slow. |
| Also note that textures written directly from the host through a mapped pointer need to be in LINEAR not OPTIMAL layout. |
| |
| \subsection usage_patterns_readback Readback |
| |
| <b>When:</b> |
| Resources that contain data written by GPU that you want to read back on CPU, |
| e.g. results of some computations. |
| |
| <b>What to do:</b> |
| Create them using #VMA_MEMORY_USAGE_GPU_TO_CPU. |
| You can write to them directly on GPU, as well as map and read them on CPU. |
| |
| \section usage_patterns_advanced Advanced patterns |
| |
| \subsection usage_patterns_integrated_graphics Detecting integrated graphics |
| |
| You can support integrated graphics (like Intel HD Graphics, AMD APU) better |
| by detecting it in Vulkan. |
| To do it, call `vkGetPhysicalDeviceProperties()`, inspect |
| `VkPhysicalDeviceProperties::deviceType` and look for `VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU`. |
| When you find it, you can assume that memory is unified and all memory types are comparably fast |
| to access from GPU, regardless of `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. |
| |
| You can then sum up sizes of all available memory heaps and treat them as useful for |
| your GPU resources, instead of only `DEVICE_LOCAL` ones. |
| You can also prefer to create your resources in memory types that are `HOST_VISIBLE` to map them |
| directly instead of submitting explicit transfer (see below). |
| |
| \subsection usage_patterns_direct_vs_transfer Direct access versus transfer |
| |
| For resources that you frequently write on CPU and read on GPU, many solutions are possible: |
| |
| -# Create one copy in video memory using #VMA_MEMORY_USAGE_GPU_ONLY, |
| second copy in system memory using #VMA_MEMORY_USAGE_CPU_ONLY and submit explicit transfer each time. |
| -# Create just a single copy using #VMA_MEMORY_USAGE_CPU_TO_GPU, map it and fill it on CPU, |
| read it directly on GPU. |
| -# Create just a single copy using #VMA_MEMORY_USAGE_CPU_ONLY, map it and fill it on CPU, |
| read it directly on GPU. |
| |
| Which solution is the most efficient depends on your resource and especially on the GPU. |
| It is best to measure it and then make the decision. |
| Some general recommendations: |
| |
| - On integrated graphics use (2) or (3) to avoid unnecesary time and memory overhead |
| related to using a second copy and making transfer. |
| - For small resources (e.g. constant buffers) use (2). |
| Discrete AMD cards have special 256 MiB pool of video memory that is directly mappable. |
| Even if the resource ends up in system memory, its data may be cached on GPU after first |
| fetch over PCIe bus. |
| - For larger resources (e.g. textures), decide between (1) and (2). |
| You may want to differentiate NVIDIA and AMD, e.g. by looking for memory type that is |
| both `DEVICE_LOCAL` and `HOST_VISIBLE`. When you find it, use (2), otherwise use (1). |
| |
| Similarly, for resources that you frequently write on GPU and read on CPU, multiple |
| solutions are possible: |
| |
| -# Create one copy in video memory using #VMA_MEMORY_USAGE_GPU_ONLY, |
| second copy in system memory using #VMA_MEMORY_USAGE_GPU_TO_CPU and submit explicit tranfer each time. |
| -# Create just single copy using #VMA_MEMORY_USAGE_GPU_TO_CPU, write to it directly on GPU, |
| map it and read it on CPU. |
| |
| You should take some measurements to decide which option is faster in case of your specific |
| resource. |
| |
| Note that textures accessed directly from the host through a mapped pointer need to be in LINEAR layout, |
| which may slow down their usage on the device. |
| Textures accessed only by the device and transfer operations can use OPTIMAL layout. |
| |
| If you don't want to specialize your code for specific types of GPUs, you can still make |
| an simple optimization for cases when your resource ends up in mappable memory to use it |
| directly in this case instead of creating CPU-side staging copy. |
| For details see [Finding out if memory is mappable](@ref memory_mapping_finding_if_memory_mappable). |
| |
| |
| \page configuration Configuration |
| |
| Please check "CONFIGURATION SECTION" in the code to find macros that you can define |
| before each include of this file or change directly in this file to provide |
| your own implementation of basic facilities like assert, `min()` and `max()` functions, |
| mutex, atomic etc. |
| The library uses its own implementation of containers by default, but you can switch to using |
| STL containers instead. |
| |
| For example, define `VMA_ASSERT(expr)` before including the library to provide |
| custom implementation of the assertion, compatible with your project. |
| By default it is defined to standard C `assert(expr)` in `_DEBUG` configuration |
| and empty otherwise. |
| |
| \section config_Vulkan_functions Pointers to Vulkan functions |
| |
| There are multiple ways to import pointers to Vulkan functions in the library. |
| In the simplest case you don't need to do anything. |
| If the compilation or linking of your program or the initialization of the #VmaAllocator |
| doesn't work for you, you can try to reconfigure it. |
| |
| First, the allocator tries to fetch pointers to Vulkan functions linked statically, |
| like this: |
| |
| \code |
| m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory; |
| \endcode |
| |
| If you want to disable this feature, set configuration macro: `#define VMA_STATIC_VULKAN_FUNCTIONS 0`. |
| |
| Second, you can provide the pointers yourself by setting member VmaAllocatorCreateInfo::pVulkanFunctions. |
| You can fetch them e.g. using functions `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` or |
| by using a helper library like [volk](https://github.com/zeux/volk). |
| |
| Third, VMA tries to fetch remaining pointers that are still null by calling |
| `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` on its own. |
| If you want to disable this feature, set configuration macro: `#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0`. |
| |
| Finally, all the function pointers required by the library (considering selected |
| Vulkan version and enabled extensions) are checked with `VMA_ASSERT` if they are not null. |
| |
| |
| \section custom_memory_allocator Custom host memory allocator |
| |
| If you use custom allocator for CPU memory rather than default operator `new` |
| and `delete` from C++, you can make this library using your allocator as well |
| by filling optional member VmaAllocatorCreateInfo::pAllocationCallbacks. These |
| functions will be passed to Vulkan, as well as used by the library itself to |
| make any CPU-side allocations. |
| |
| \section allocation_callbacks Device memory allocation callbacks |
| |
| The library makes calls to `vkAllocateMemory()` and `vkFreeMemory()` internally. |
| You can setup callbacks to be informed about these calls, e.g. for the purpose |
| of gathering some statistics. To do it, fill optional member |
| VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. |
| |
| \section heap_memory_limit Device heap memory limit |
| |
| When device memory of certain heap runs out of free space, new allocations may |
| fail (returning error code) or they may succeed, silently pushing some existing |
| memory blocks from GPU VRAM to system RAM (which degrades performance). This |
| behavior is implementation-dependant - it depends on GPU vendor and graphics |
| driver. |
| |
| On AMD cards it can be controlled while creating Vulkan device object by using |
| VK_AMD_memory_overallocation_behavior extension, if available. |
| |
| Alternatively, if you want to test how your program behaves with limited amount of Vulkan device |
| memory available without switching your graphics card to one that really has |
| smaller VRAM, you can use a feature of this library intended for this purpose. |
| To do it, fill optional member VmaAllocatorCreateInfo::pHeapSizeLimit. |
| |
| |
| |
| \page vk_khr_dedicated_allocation VK_KHR_dedicated_allocation |
| |
| VK_KHR_dedicated_allocation is a Vulkan extension which can be used to improve |
| performance on some GPUs. It augments Vulkan API with possibility to query |
| driver whether it prefers particular buffer or image to have its own, dedicated |
| allocation (separate `VkDeviceMemory` block) for better efficiency - to be able |
| to do some internal optimizations. |
| |
| The extension is supported by this library. It will be used automatically when |
| enabled. To enable it: |
| |
| 1 . When creating Vulkan device, check if following 2 device extensions are |
| supported (call `vkEnumerateDeviceExtensionProperties()`). |
| If yes, enable them (fill `VkDeviceCreateInfo::ppEnabledExtensionNames`). |
| |
| - VK_KHR_get_memory_requirements2 |
| - VK_KHR_dedicated_allocation |
| |
| If you enabled these extensions: |
| |
| 2 . Use #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag when creating |
| your #VmaAllocator`to inform the library that you enabled required extensions |
| and you want the library to use them. |
| |
| \code |
| allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; |
| |
| vmaCreateAllocator(&allocatorInfo, &allocator); |
| \endcode |
| |
| That's all. The extension will be automatically used whenever you create a |
| buffer using vmaCreateBuffer() or image using vmaCreateImage(). |
| |
| When using the extension together with Vulkan Validation Layer, you will receive |
| warnings like this: |
| |
| vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer. |
| |
| It is OK, you should just ignore it. It happens because you use function |
| `vkGetBufferMemoryRequirements2KHR()` instead of standard |
| `vkGetBufferMemoryRequirements()`, while the validation layer seems to be |
| unaware of it. |
| |
| To learn more about this extension, see: |
| |
| - [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap44.html#VK_KHR_dedicated_allocation) |
| - [VK_KHR_dedicated_allocation unofficial manual](http://asawicki.info/articles/VK_KHR_dedicated_allocation.php5) |
| |
| |
| |
| \page vk_amd_device_coherent_memory VK_AMD_device_coherent_memory |
| |
| VK_AMD_device_coherent_memory is a device extension that enables access to |
| additional memory types with `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and |
| `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flag. It is useful mostly for |
| allocation of buffers intended for writing "breadcrumb markers" in between passes |
| or draw calls, which in turn are useful for debugging GPU crash/hang/TDR cases. |
| |
| When the extension is available but has not been enabled, Vulkan physical device |
| still exposes those memory types, but their usage is forbidden. VMA automatically |
| takes care of that - it returns `VK_ERROR_FEATURE_NOT_PRESENT` when an attempt |
| to allocate memory of such type is made. |
| |
| If you want to use this extension in connection with VMA, follow these steps: |
| |
| \section vk_amd_device_coherent_memory_initialization Initialization |
| |
| 1) Call `vkEnumerateDeviceExtensionProperties` for the physical device. |
| Check if the extension is supported - if returned array of `VkExtensionProperties` contains "VK_AMD_device_coherent_memory". |
| |
| 2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. |
| Attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to `VkPhysicalDeviceFeatures2::pNext` to be returned. |
| Check if the device feature is really supported - check if `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true. |
| |
| 3) While creating device with `vkCreateDevice`, enable this extension - add "VK_AMD_device_coherent_memory" |
| to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. |
| |
| 4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. |
| Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. |
| Enable this device feature - attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to |
| `VkPhysicalDeviceFeatures2::pNext` and set its member `deviceCoherentMemory` to `VK_TRUE`. |
| |
| 5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you |
| have enabled this extension and feature - add #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT |
| to VmaAllocatorCreateInfo::flags. |
| |
| \section vk_amd_device_coherent_memory_usage Usage |
| |
| After following steps described above, you can create VMA allocations and custom pools |
| out of the special `DEVICE_COHERENT` and `DEVICE_UNCACHED` memory types on eligible |
| devices. There are multiple ways to do it, for example: |
| |
| - You can request or prefer to allocate out of such memory types by adding |
| `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` to VmaAllocationCreateInfo::requiredFlags |
| or VmaAllocationCreateInfo::preferredFlags. Those flags can be freely mixed with |
| other ways of \ref choosing_memory_type, like setting VmaAllocationCreateInfo::usage. |
| - If you manually found memory type index to use for this purpose, force allocation |
| from this specific index by setting VmaAllocationCreateInfo::memoryTypeBits `= 1u << index`. |
| |
| \section vk_amd_device_coherent_memory_more_information More information |
| |
| To learn more about this extension, see [VK_AMD_device_coherent_memory in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap44.html#VK_AMD_device_coherent_memory) |
| |
| Example use of this extension can be found in the code of the sample and test suite |
| accompanying this library. |
| |
| |
| \page enabling_buffer_device_address Enabling buffer device address |
| |
| Device extension VK_KHR_buffer_device_address |
| allow to fetch raw GPU pointer to a buffer and pass it for usage in a shader code. |
| It is promoted to core Vulkan 1.2. |
| |
| If you want to use this feature in connection with VMA, follow these steps: |
| |
| \section enabling_buffer_device_address_initialization Initialization |
| |
| 1) (For Vulkan version < 1.2) Call `vkEnumerateDeviceExtensionProperties` for the physical device. |
| Check if the extension is supported - if returned array of `VkExtensionProperties` contains |
| "VK_KHR_buffer_device_address". |
| |
| 2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. |
| Attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to `VkPhysicalDeviceFeatures2::pNext` to be returned. |
| Check if the device feature is really supported - check if `VkPhysicalDeviceBufferDeviceAddressFeatures*::bufferDeviceAddress` is true. |
| |
| 3) (For Vulkan version < 1.2) While creating device with `vkCreateDevice`, enable this extension - add |
| "VK_KHR_buffer_device_address" to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. |
| |
| 4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. |
| Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. |
| Enable this device feature - attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to |
| `VkPhysicalDeviceFeatures2::pNext` and set its member `bufferDeviceAddress` to `VK_TRUE`. |
| |
| 5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you |
| have enabled this feature - add #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT |
| to VmaAllocatorCreateInfo::flags. |
| |
| \section enabling_buffer_device_address_usage Usage |
| |
| After following steps described above, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*` using VMA. |
| The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT*` to |
| allocated memory blocks wherever it might be needed. |
| |
| Please note that the library supports only `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*`. |
| The second part of this functionality related to "capture and replay" is not supported, |
| as it is intended for usage in debugging tools like RenderDoc, not in everyday Vulkan usage. |
| |
| \section enabling_buffer_device_address_more_information More information |
| |
| To learn more about this extension, see [VK_KHR_buffer_device_address in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap46.html#VK_KHR_buffer_device_address) |
| |
| Example use of this extension can be found in the code of the sample and test suite |
| accompanying this library. |
| |
| \page general_considerations General considerations |
| |
| \section general_considerations_thread_safety Thread safety |
| |
| - The library has no global state, so separate #VmaAllocator objects can be used |
| independently. |
| There should be no need to create multiple such objects though - one per `VkDevice` is enough. |
| - By default, all calls to functions that take #VmaAllocator as first parameter |
| are safe to call from multiple threads simultaneously because they are |
| synchronized internally when needed. |
| - When the allocator is created with #VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT |
| flag, calls to functions that take such #VmaAllocator object must be |
| synchronized externally. |
| - Access to a #VmaAllocation object must be externally synchronized. For example, |
| you must not call vmaGetAllocationInfo() and vmaMapMemory() from different |
| threads at the same time if you pass the same #VmaAllocation object to these |
| functions. |
| |
| \section general_considerations_validation_layer_warnings Validation layer warnings |
| |
| When using this library, you can meet following types of warnings issued by |
| Vulkan validation layer. They don't necessarily indicate a bug, so you may need |
| to just ignore them. |
| |
| - *vkBindBufferMemory(): Binding memory to buffer 0xeb8e4 but vkGetBufferMemoryRequirements() has not been called on that buffer.* |
| - It happens when VK_KHR_dedicated_allocation extension is enabled. |
| `vkGetBufferMemoryRequirements2KHR` function is used instead, while validation layer seems to be unaware of it. |
| - *Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used.* |
| - It happens when you map a buffer or image, because the library maps entire |
| `VkDeviceMemory` block, where different types of images and buffers may end |
| up together, especially on GPUs with unified memory like Intel. |
| - *Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug.* |
| - It happens when you use lost allocations, and a new image or buffer is |
| created in place of an existing object that bacame lost. |
| - It may happen also when you use [defragmentation](@ref defragmentation). |
| |
| \section general_considerations_allocation_algorithm Allocation algorithm |
| |
| The library uses following algorithm for allocation, in order: |
| |
| -# Try to find free range of memory in existing blocks. |
| -# If failed, try to create a new block of `VkDeviceMemory`, with preferred block size. |
| -# If failed, try to create such block with size/2, size/4, size/8. |
| -# If failed and #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag was |
| specified, try to find space in existing blocks, possilby making some other |
| allocations lost. |
| -# If failed, try to allocate separate `VkDeviceMemory` for this allocation, |
| just like when you use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. |
| -# If failed, choose other memory type that meets the requirements specified in |
| VmaAllocationCreateInfo and go to point 1. |
| -# If failed, return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. |
| |
| \section general_considerations_features_not_supported Features not supported |
| |
| Features deliberately excluded from the scope of this library: |
| |
| - Data transfer. Uploading (straming) and downloading data of buffers and images |
| between CPU and GPU memory and related synchronization is responsibility of the user. |
| Defining some "texture" object that would automatically stream its data from a |
| staging copy in CPU memory to GPU memory would rather be a feature of another, |
| higher-level library implemented on top of VMA. |
| - 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 `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. |
| - This is a C++ library with C interface. |
| Bindings or ports to any other programming languages are welcomed as external projects and |
| are not going to be included into this repository. |
| |
| */ |
| |
| #if VMA_RECORDING_ENABLED |
| #include <chrono> |
| #if defined(_WIN32) |
| #include <windows.h> |
| #else |
| #include <sstream> |
| #include <thread> |
| #endif |
| #endif |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* |
| Define this macro to 0/1 to disable/enable support for recording functionality, |
| available through VmaAllocatorCreateInfo::pRecordSettings. |
| */ |
| #ifndef VMA_RECORDING_ENABLED |
| #define VMA_RECORDING_ENABLED 0 |
| #endif |
| |
| #ifndef NOMINMAX |
| #define NOMINMAX // For windows.h |
| #endif |
| |
| #if defined(__ANDROID__) && defined(VK_NO_PROTOTYPES) && VMA_STATIC_VULKAN_FUNCTIONS |
| extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; |
| extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; |
| extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; |
| extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; |
| extern PFN_vkAllocateMemory vkAllocateMemory; |
| extern PFN_vkFreeMemory vkFreeMemory; |
| extern PFN_vkMapMemory vkMapMemory; |
| extern PFN_vkUnmapMemory vkUnmapMemory; |
| extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; |
| extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; |
| extern PFN_vkBindBufferMemory vkBindBufferMemory; |
| extern PFN_vkBindImageMemory vkBindImageMemory; |
| extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; |
| extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; |
| extern PFN_vkCreateBuffer vkCreateBuffer; |
| extern PFN_vkDestroyBuffer vkDestroyBuffer; |
| extern PFN_vkCreateImage vkCreateImage; |
| extern PFN_vkDestroyImage vkDestroyImage; |
| extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; |
| #if VMA_VULKAN_VERSION >= 1001000 |
| extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; |
| extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; |
| extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; |
| extern PFN_vkBindImageMemory2 vkBindImageMemory2; |
| extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; |
| #endif // #if VMA_VULKAN_VERSION >= 1001000 |
| #endif // #if defined(__ANDROID__) && VMA_STATIC_VULKAN_FUNCTIONS && VK_NO_PROTOTYPES |
| |
| #ifndef VULKAN_H_ |
| // For skia we don't include vulkan.h here. Before including this header we always include |
| // Skias internal vulkan header which should have everything we need. We can't depend on the |
| // VULKAN_H_ guard casue skia just inclues vulkan_core.h which doesn't not set the general |
| // vulkan guard. |
| //#include <vulkan/vulkan.h> |
| #endif |
| |
| // Define this macro to declare maximum supported Vulkan version in format AAABBBCCC, |
| // where AAA = major, BBB = minor, CCC = patch. |
| // If you want to use version > 1.0, it still needs to be enabled via VmaAllocatorCreateInfo::vulkanApiVersion. |
| #if !defined(VMA_VULKAN_VERSION) |
| #if defined(VK_VERSION_1_2) |
| #define VMA_VULKAN_VERSION 1002000 |
| #elif defined(VK_VERSION_1_1) |
| #define VMA_VULKAN_VERSION 1001000 |
| #else |
| #define VMA_VULKAN_VERSION 1000000 |
| #endif |
| #endif |
| |
| #if !defined(VMA_DEDICATED_ALLOCATION) |
| #if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation |
| #define VMA_DEDICATED_ALLOCATION 1 |
| #else |
| #define VMA_DEDICATED_ALLOCATION 0 |
| #endif |
| #endif |
| |
| #if !defined(VMA_BIND_MEMORY2) |
| #if VK_KHR_bind_memory2 |
| #define VMA_BIND_MEMORY2 1 |
| #else |
| #define VMA_BIND_MEMORY2 0 |
| #endif |
| #endif |
| |
| #if !defined(VMA_MEMORY_BUDGET) |
| #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) |
| #define VMA_MEMORY_BUDGET 1 |
| #else |
| #define VMA_MEMORY_BUDGET 0 |
| #endif |
| #endif |
| |
| // Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. |
| #if !defined(VMA_BUFFER_DEVICE_ADDRESS) |
| #if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 |
| #define VMA_BUFFER_DEVICE_ADDRESS 1 |
| #else |
| #define VMA_BUFFER_DEVICE_ADDRESS 0 |
| #endif |
| #endif |
| |
| // Define these macros to decorate all public functions with additional code, |
| // before and after returned type, appropriately. This may be useful for |
| // exporing the functions when compiling VMA as a separate library. Example: |
| // #define VMA_CALL_PRE __declspec(dllexport) |
| // #define VMA_CALL_POST __cdecl |
| #ifndef VMA_CALL_PRE |
| #define VMA_CALL_PRE |
| #endif |
| #ifndef VMA_CALL_POST |
| #define VMA_CALL_POST |
| #endif |
| |
| // Define this macro to decorate pointers with an attribute specifying the |
| // length of the array they point to if they are not null. |
| // |
| // The length may be one of |
| // - The name of another parameter in the argument list where the pointer is declared |
| // - The name of another member in the struct where the pointer is declared |
| // - The name of a member of a struct type, meaning the value of that member in |
| // the context of the call. For example |
| // VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount"), |
| // this means the number of memory heaps available in the device associated |
| // with the VmaAllocator being dealt with. |
| #ifndef VMA_LEN_IF_NOT_NULL |
| #define VMA_LEN_IF_NOT_NULL(len) |
| #endif |
| |
| // The VMA_NULLABLE macro is defined to be _Nullable when compiling with Clang. |
| // see: https://clang.llvm.org/docs/AttributeReference.html#nullable |
| #ifndef VMA_NULLABLE |
| #ifdef __clang__ |
| #define VMA_NULLABLE _Nullable |
| #else |
| #define VMA_NULLABLE |
| #endif |
| #endif |
| |
| // The VMA_NOT_NULL macro is defined to be _Nonnull when compiling with Clang. |
| // see: https://clang.llvm.org/docs/AttributeReference.html#nonnull |
| #ifndef VMA_NOT_NULL |
| #ifdef __clang__ |
| #define VMA_NOT_NULL _Nonnull |
| #else |
| #define VMA_NOT_NULL |
| #endif |
| #endif |
| |
| // If non-dispatchable handles are represented as pointers then we can give |
| // then nullability annotations |
| #ifndef VMA_NOT_NULL_NON_DISPATCHABLE |
| #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) |
| #define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL |
| #else |
| #define VMA_NOT_NULL_NON_DISPATCHABLE |
| #endif |
| #endif |
| |
| #ifndef VMA_NULLABLE_NON_DISPATCHABLE |
| #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) |
| #define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE |
| #else |
| #define VMA_NULLABLE_NON_DISPATCHABLE |
| #endif |
| #endif |
| |
| /** \struct VmaAllocator |
| \brief Represents main object of this library initialized. |
| |
| Fill structure #VmaAllocatorCreateInfo and call function vmaCreateAllocator() to create it. |
| Call function vmaDestroyAllocator() to destroy it. |
| |
| It is recommended to create just one object of this type per `VkDevice` object, |
| right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. |
| */ |
| VK_DEFINE_HANDLE(VmaAllocator) |
| |
| /// Callback function called after successful vkAllocateMemory. |
| typedef void (VKAPI_PTR *PFN_vmaAllocateDeviceMemoryFunction)( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t memoryType, |
| VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, |
| VkDeviceSize size, |
| void* VMA_NULLABLE pUserData); |
| /// Callback function called before vkFreeMemory. |
| typedef void (VKAPI_PTR *PFN_vmaFreeDeviceMemoryFunction)( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t memoryType, |
| VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, |
| VkDeviceSize size, |
| void* VMA_NULLABLE pUserData); |
| |
| /** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. |
| |
| Provided for informative purpose, e.g. to gather statistics about number of |
| allocations or total amount of memory allocated in Vulkan. |
| |
| Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. |
| */ |
| typedef struct VmaDeviceMemoryCallbacks { |
| /// Optional, can be null. |
| PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; |
| /// Optional, can be null. |
| PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; |
| /// Optional, can be null. |
| void* VMA_NULLABLE pUserData; |
| } VmaDeviceMemoryCallbacks; |
| |
| /// Flags for created #VmaAllocator. |
| typedef enum VmaAllocatorCreateFlagBits { |
| /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. |
| |
| Using this flag may increase performance because internal mutexes are not used. |
| */ |
| VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, |
| /** \brief Enables usage of VK_KHR_dedicated_allocation extension. |
| |
| The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. |
| When it's `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. |
| |
| Using this extenion will automatically allocate dedicated blocks of memory for |
| some buffers and images instead of suballocating place for them out of bigger |
| memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT |
| flag) when it is recommended by the driver. It may improve performance on some |
| GPUs. |
| |
| You may set this flag only if you found out that following device extensions are |
| supported, you enabled them while creating Vulkan device passed as |
| VmaAllocatorCreateInfo::device, and you want them to be used internally by this |
| library: |
| |
| - VK_KHR_get_memory_requirements2 (device extension) |
| - VK_KHR_dedicated_allocation (device extension) |
| |
| When this flag is set, you can experience following warnings reported by Vulkan |
| validation layer. You can ignore them. |
| |
| > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. |
| */ |
| VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, |
| /** |
| Enables usage of VK_KHR_bind_memory2 extension. |
| |
| The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. |
| When it's `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. |
| |
| You may set this flag only if you found out that this device extension is supported, |
| you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, |
| and you want it to be used internally by this library. |
| |
| The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, |
| which allow to pass a chain of `pNext` structures while binding. |
| This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). |
| */ |
| VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, |
| /** |
| Enables usage of VK_EXT_memory_budget extension. |
| |
| You may set this flag only if you found out that this device extension is supported, |
| you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, |
| and you want it to be used internally by this library, along with another instance extension |
| VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). |
| |
| The extension provides query for current memory usage and budget, which will probably |
| be more accurate than an estimation used by the library otherwise. |
| */ |
| VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, |
| /** |
| Enables usage of VK_AMD_device_coherent_memory extension. |
| |
| You may set this flag only if you: |
| |
| - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, |
| - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, |
| - want it to be used internally by this library. |
| |
| The extension and accompanying device feature provide access to memory types with |
| `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. |
| They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. |
| |
| When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. |
| To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, |
| returning `VK_ERROR_FEATURE_NOT_PRESENT`. |
| */ |
| VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, |
| /** |
| Enables usage of "buffer device address" feature, which allows you to use function |
| `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. |
| |
| You may set this flag only if you: |
| |
| 1. (For Vulkan version < 1.2) Found as available and enabled device extension |
| VK_KHR_buffer_device_address. |
| This extension is promoted to core Vulkan 1.2. |
| 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures*::bufferDeviceAddress`. |
| |
| When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*` using VMA. |
| The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT*` to |
| allocated memory blocks wherever it might be needed. |
| |
| For more information, see documentation chapter \ref enabling_buffer_device_address. |
| */ |
| VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, |
| |
| VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF |
| } VmaAllocatorCreateFlagBits; |
| typedef VkFlags VmaAllocatorCreateFlags; |
| |
| /** \brief Pointers to some Vulkan functions - a subset used by the library. |
| |
| Used in VmaAllocatorCreateInfo::pVulkanFunctions. |
| */ |
| typedef struct VmaVulkanFunctions { |
| PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; |
| PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; |
| PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; |
| PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; |
| PFN_vkMapMemory VMA_NULLABLE vkMapMemory; |
| PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; |
| PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; |
| PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; |
| PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; |
| PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; |
| PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; |
| PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; |
| PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; |
| PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; |
| PFN_vkCreateImage VMA_NULLABLE vkCreateImage; |
| PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; |
| PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; |
| #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 |
| PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; |
| PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; |
| #endif |
| #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 |
| PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; |
| PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; |
| #endif |
| #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 |
| PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; |
| #endif |
| } VmaVulkanFunctions; |
| |
| /// Flags to be used in VmaRecordSettings::flags. |
| typedef enum VmaRecordFlagBits { |
| /** \brief Enables flush after recording every function call. |
| |
| Enable it if you expect your application to crash, which may leave recording file truncated. |
| It may degrade performance though. |
| */ |
| VMA_RECORD_FLUSH_AFTER_CALL_BIT = 0x00000001, |
| |
| VMA_RECORD_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF |
| } VmaRecordFlagBits; |
| typedef VkFlags VmaRecordFlags; |
| |
| /// Parameters for recording calls to VMA functions. To be used in VmaAllocatorCreateInfo::pRecordSettings. |
| typedef struct VmaRecordSettings |
| { |
| /// Flags for recording. Use #VmaRecordFlagBits enum. |
| VmaRecordFlags flags; |
| /** \brief Path to the file that should be written by the recording. |
| |
| Suggested extension: "csv". |
| If the file already exists, it will be overwritten. |
| It will be opened for the whole time #VmaAllocator object is alive. |
| If opening this file fails, creation of the whole allocator object fails. |
| */ |
| const char* VMA_NOT_NULL pFilePath; |
| } VmaRecordSettings; |
| |
| /// Description of a Allocator to be created. |
| typedef struct VmaAllocatorCreateInfo |
| { |
| /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. |
| VmaAllocatorCreateFlags flags; |
| /// Vulkan physical device. |
| /** It must be valid throughout whole lifetime of created allocator. */ |
| VkPhysicalDevice VMA_NOT_NULL physicalDevice; |
| /// Vulkan device. |
| /** It must be valid throughout whole lifetime of created allocator. */ |
| VkDevice VMA_NOT_NULL device; |
| /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. |
| /** Set to 0 to use default, which is currently 256 MiB. */ |
| VkDeviceSize preferredLargeHeapBlockSize; |
| /// Custom CPU memory allocation callbacks. Optional. |
| /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ |
| const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; |
| /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. |
| /** Optional, can be null. */ |
| const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; |
| /** \brief Maximum number of additional frames that are in use at the same time as current frame. |
| |
| This value is used only when you make allocations with |
| VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become |
| lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount. |
| |
| For example, if you double-buffer your command buffers, so resources used for |
| rendering in previous frame may still be in use by the GPU at the moment you |
| allocate resources needed for the current frame, set this value to 1. |
| |
| If you want to allow any allocations other than used in the current frame to |
| become lost, set this value to 0. |
| */ |
| uint32_t frameInUseCount; |
| /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. |
| |
| If not NULL, it must be a pointer to an array of |
| `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on |
| maximum number of bytes that can be allocated out of particular Vulkan memory |
| heap. |
| |
| Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that |
| heap. This is also the default in case of `pHeapSizeLimit` = NULL. |
| |
| If there is a limit defined for a heap: |
| |
| - If user tries to allocate more memory from that heap using this allocator, |
| the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. |
| - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the |
| value of this limit will be reported instead when using vmaGetMemoryProperties(). |
| |
| 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 `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. This driver behavior can also be controlled using |
| VK_AMD_memory_overallocation_behavior extension. |
| */ |
| const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; |
| |
| /** \brief Pointers to Vulkan functions. Can be null. |
| |
| For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). |
| */ |
| const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; |
| /** \brief Parameters for recording of VMA calls. Can be null. |
| |
| If not null, it enables recording of calls to VMA functions to a file. |
| If support for recording is not enabled using `VMA_RECORDING_ENABLED` macro, |
| creation of the allocator object fails with `VK_ERROR_FEATURE_NOT_PRESENT`. |
| */ |
| const VmaRecordSettings* VMA_NULLABLE pRecordSettings; |
| /** \brief Handle to Vulkan instance object. |
| |
| Starting from version 3.0.0 this member is no longer optional, it must be set! |
| */ |
| VkInstance VMA_NOT_NULL instance; |
| /** \brief Optional. The highest version of Vulkan that the application is designed to use. |
| |
| It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. |
| The patch version number specified is ignored. Only the major and minor versions are considered. |
| It must be less or equal (preferably equal) to value as passed to `vkCreateInstance` as `VkApplicationInfo::apiVersion`. |
| Only versions 1.0 and 1.1 are supported by the current implementation. |
| Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. |
| */ |
| uint32_t vulkanApiVersion; |
| } VmaAllocatorCreateInfo; |
| |
| /// Creates Allocator object. |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( |
| const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, |
| VmaAllocator VMA_NULLABLE * VMA_NOT_NULL pAllocator); |
| |
| /// Destroys allocator object. |
| VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( |
| VmaAllocator VMA_NULLABLE allocator); |
| |
| /** \brief Information about existing #VmaAllocator object. |
| */ |
| typedef struct VmaAllocatorInfo |
| { |
| /** \brief Handle to Vulkan instance object. |
| |
| This is the same value as has been passed through VmaAllocatorCreateInfo::instance. |
| */ |
| VkInstance VMA_NOT_NULL instance; |
| /** \brief Handle to Vulkan physical device object. |
| |
| This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. |
| */ |
| VkPhysicalDevice VMA_NOT_NULL physicalDevice; |
| /** \brief Handle to Vulkan device object. |
| |
| This is the same value as has been passed through VmaAllocatorCreateInfo::device. |
| */ |
| VkDevice VMA_NOT_NULL device; |
| } VmaAllocatorInfo; |
| |
| /** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. |
| |
| It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to |
| `VkPhysicalDevice`, `VkDevice` etc. every time using this function. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator VMA_NOT_NULL allocator, VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); |
| |
| /** |
| PhysicalDeviceProperties are fetched from physicalDevice by the allocator. |
| You can access it here, without fetching it again on your own. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VkPhysicalDeviceProperties* VMA_NULLABLE * VMA_NOT_NULL ppPhysicalDeviceProperties); |
| |
| /** |
| PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. |
| You can access it here, without fetching it again on your own. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE * VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); |
| |
| /** |
| \brief Given Memory Type Index, returns Property Flags of this memory type. |
| |
| This is just a convenience function. Same information can be obtained using |
| vmaGetMemoryProperties(). |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t memoryTypeIndex, |
| VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); |
| |
| /** \brief Sets index of the current frame. |
| |
| This function must be used if you make allocations with |
| #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT and |
| #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flags to inform the allocator |
| when a new frame begins. Allocations queried using vmaGetAllocationInfo() cannot |
| become lost in the current frame. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t frameIndex); |
| |
| /** \brief Calculated statistics of memory usage in entire allocator. |
| */ |
| typedef struct VmaStatInfo |
| { |
| /// Number of `VkDeviceMemory` Vulkan memory blocks allocated. |
| uint32_t blockCount; |
| /// Number of #VmaAllocation allocation objects allocated. |
| uint32_t allocationCount; |
| /// Number of free ranges of memory between allocations. |
| uint32_t unusedRangeCount; |
| /// Total number of bytes occupied by all allocations. |
| VkDeviceSize usedBytes; |
| /// Total number of bytes occupied by unused ranges. |
| VkDeviceSize unusedBytes; |
| VkDeviceSize allocationSizeMin, allocationSizeAvg, allocationSizeMax; |
| VkDeviceSize unusedRangeSizeMin, unusedRangeSizeAvg, unusedRangeSizeMax; |
| } VmaStatInfo; |
| |
| /// General statistics from current state of Allocator. |
| typedef struct VmaStats |
| { |
| VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES]; |
| VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS]; |
| VmaStatInfo total; |
| } VmaStats; |
| |
| /** \brief Retrieves statistics from current state of the Allocator. |
| |
| This function is called "calculate" not "get" because it has to traverse all |
| internal data structures, so it may be quite slow. For faster but more brief statistics |
| suitable to be called every frame or every allocation, use vmaGetBudget(). |
| |
| Note that when using allocator from multiple threads, returned information may immediately |
| become outdated. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaStats* VMA_NOT_NULL pStats); |
| |
| /** \brief Statistics of current memory usage and available budget, in bytes, for specific memory heap. |
| */ |
| typedef struct VmaBudget |
| { |
| /** \brief Sum size of all `VkDeviceMemory` blocks allocated from particular heap, in bytes. |
| */ |
| VkDeviceSize blockBytes; |
| |
| /** \brief Sum size of all allocations created in particular heap, in bytes. |
| |
| Usually less or equal than `blockBytes`. |
| Difference `blockBytes - allocationBytes` is the amount of memory allocated but unused - |
| available for new allocations or wasted due to fragmentation. |
| |
| It might be greater than `blockBytes` if there are some allocations in lost state, as they account |
| to this value as well. |
| */ |
| VkDeviceSize allocationBytes; |
| |
| /** \brief Estimated current memory usage of the program, in bytes. |
| |
| Fetched from system using `VK_EXT_memory_budget` extension if enabled. |
| |
| It might be different than `blockBytes` (usually higher) due to additional implicit objects |
| also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or |
| `VkDeviceMemory` blocks allocated outside of this library, if any. |
| */ |
| VkDeviceSize usage; |
| |
| /** \brief Estimated amount of memory available to the program, in bytes. |
| |
| Fetched from system using `VK_EXT_memory_budget` extension if enabled. |
| |
| It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors |
| external to the program, like other programs also consuming system resources. |
| Difference `budget - usage` is the amount of additional memory that can probably |
| be allocated without problems. Exceeding the budget may result in various problems. |
| */ |
| VkDeviceSize budget; |
| } VmaBudget; |
| |
| /** \brief Retrieves information about current memory budget for all memory heaps. |
| |
| \param[out] pBudget Must point to array with number of elements at least equal to number of memory heaps in physical device used. |
| |
| This function is called "get" not "calculate" because it is very fast, suitable to be called |
| every frame or every allocation. For more detailed statistics use vmaCalculateStats(). |
| |
| Note that when using allocator from multiple threads, returned information may immediately |
| become outdated. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaBudget* VMA_NOT_NULL pBudget); |
| |
| #ifndef VMA_STATS_STRING_ENABLED |
| #define VMA_STATS_STRING_ENABLED 1 |
| #endif |
| |
| #if VMA_STATS_STRING_ENABLED |
| |
| /// Builds and returns statistics as string in JSON format. |
| /** @param[out] ppStatsString Must be freed using vmaFreeStatsString() function. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( |
| VmaAllocator VMA_NOT_NULL allocator, |
| char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, |
| VkBool32 detailedMap); |
| |
| VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( |
| VmaAllocator VMA_NOT_NULL allocator, |
| char* VMA_NULLABLE pStatsString); |
| |
| #endif // #if VMA_STATS_STRING_ENABLED |
| |
| /** \struct VmaPool |
| \brief Represents custom memory pool |
| |
| Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. |
| Call function vmaDestroyPool() to destroy it. |
| |
| For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). |
| */ |
| VK_DEFINE_HANDLE(VmaPool) |
| |
| typedef enum VmaMemoryUsage |
| { |
| /** No intended memory usage specified. |
| Use other members of VmaAllocationCreateInfo to specify your requirements. |
| */ |
| VMA_MEMORY_USAGE_UNKNOWN = 0, |
| /** Memory will be used on device only, so fast access from the device is preferred. |
| It usually means device-local GPU (video) memory. |
| No need to be mappable on host. |
| It is roughly equivalent of `D3D12_HEAP_TYPE_DEFAULT`. |
| |
| Usage: |
| |
| - Resources written and read by device, e.g. images used as attachments. |
| - Resources transferred from host once (immutable) or infrequently and read by |
| device multiple times, e.g. textures to be sampled, vertex buffers, uniform |
| (constant) buffers, and majority of other types of resources used on GPU. |
| |
| Allocation may still end up in `HOST_VISIBLE` memory on some implementations. |
| In such case, you are free to map it. |
| You can use #VMA_ALLOCATION_CREATE_MAPPED_BIT with this usage type. |
| */ |
| VMA_MEMORY_USAGE_GPU_ONLY = 1, |
| /** Memory will be mappable on host. |
| It usually means CPU (system) memory. |
| Guarantees to be `HOST_VISIBLE` and `HOST_COHERENT`. |
| CPU access is typically uncached. Writes may be write-combined. |
| Resources created in this pool may still be accessible to the device, but access to them can be slow. |
| It is roughly equivalent of `D3D12_HEAP_TYPE_UPLOAD`. |
| |
| Usage: Staging copy of resources used as transfer source. |
| */ |
| VMA_MEMORY_USAGE_CPU_ONLY = 2, |
| /** |
| Memory that is both mappable on host (guarantees to be `HOST_VISIBLE`) and preferably fast to access by GPU. |
| CPU access is typically uncached. Writes may be write-combined. |
| |
| Usage: Resources written frequently by host (dynamic), read by device. E.g. textures (with LINEAR layout), vertex buffers, uniform buffers updated every frame or every draw call. |
| */ |
| VMA_MEMORY_USAGE_CPU_TO_GPU = 3, |
| /** Memory mappable on host (guarantees to be `HOST_VISIBLE`) and cached. |
| It is roughly equivalent of `D3D12_HEAP_TYPE_READBACK`. |
| |
| Usage: |
| |
| - Resources written by device, read by host - results of some computations, e.g. screen capture, average scene luminance for HDR tone mapping. |
| - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection. |
| */ |
| VMA_MEMORY_USAGE_GPU_TO_CPU = 4, |
| /** CPU memory - memory that is preferably not `DEVICE_LOCAL`, but also not guaranteed to be `HOST_VISIBLE`. |
| |
| Usage: Staging copy of resources moved from GPU memory to CPU memory as part |
| of custom paging/residency mechanism, to be moved back to GPU memory when needed. |
| */ |
| VMA_MEMORY_USAGE_CPU_COPY = 5, |
| /** Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. |
| Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. |
| |
| Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. |
| |
| Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. |
| */ |
| VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, |
| |
| VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF |
| } VmaMemoryUsage; |
| |
| /// Flags to be passed as VmaAllocationCreateInfo::flags. |
| typedef enum VmaAllocationCreateFlagBits { |
| /** \brief Set this flag if the allocation should have its own memory block. |
| |
| Use it for special, big resources, like fullscreen images used as attachments. |
| |
| You should not use this flag if VmaAllocationCreateInfo::pool is not null. |
| */ |
| VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, |
| |
| /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. |
| |
| If new allocation cannot be placed in any of the existing blocks, allocation |
| fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. |
| |
| You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and |
| #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. |
| |
| If VmaAllocationCreateInfo::pool is not null, this flag is implied and ignored. */ |
| VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, |
| /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. |
| |
| Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. |
| |
| Is it valid to use this flag for allocation made from memory type that is not |
| `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is |
| useful if you need an allocation that is efficient to use on GPU |
| (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that |
| support it (e.g. Intel GPU). |
| |
| You should not use this flag together with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT. |
| */ |
| VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, |
| /** Allocation created with this flag can become lost as a result of another |
| allocation with #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag, so you |
| must check it before use. |
| |
| To check if allocation is not lost, call vmaGetAllocationInfo() and check if |
| VmaAllocationInfo::deviceMemory is not `VK_NULL_HANDLE`. |
| |
| For details about supporting lost allocations, see Lost Allocations |
| chapter of User Guide on Main Page. |
| |
| You should not use this flag together with #VMA_ALLOCATION_CREATE_MAPPED_BIT. |
| */ |
| VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT = 0x00000008, |
| /** While creating allocation using this flag, other allocations that were |
| created with flag #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT can become lost. |
| |
| For details about supporting lost allocations, see Lost Allocations |
| chapter of User Guide on Main Page. |
| */ |
| VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT = 0x00000010, |
| /** Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a |
| null-terminated string. Instead of copying pointer value, a local copy of the |
| string is made and stored in allocation's `pUserData`. The string is automatically |
| freed together with the allocation. It is also used in vmaBuildStatsString(). |
| */ |
| VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, |
| /** Allocation will be created from upper stack in a double stack pool. |
| |
| This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. |
| */ |
| VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, |
| /** Create both buffer/image and allocation, but don't bind them together. |
| It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. |
| The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). |
| Otherwise it is ignored. |
| */ |
| VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, |
| /** Create allocation only if additional device memory required for it, if any, won't exceed |
| memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. |
| */ |
| VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, |
| |
| /** Allocation strategy that chooses smallest possible free range for the |
| allocation. |
| */ |
| VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = 0x00010000, |
| /** Allocation strategy that chooses biggest possible free range for the |
| allocation. |
| */ |
| 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, |
| |
| /** Allocation strategy that tries to minimize memory usage. |
| */ |
| VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT, |
| /** Allocation strategy that tries to minimize allocation time. |
| */ |
| VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT, |
| /** Allocation strategy that tries to minimize memory fragmentation. |
| */ |
| VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT = VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT, |
| |
| /** A bit mask to extract only `STRATEGY` bits from entire set of flags. |
| */ |
| VMA_ALLOCATION_CREATE_STRATEGY_MASK = |
| VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT | |
| VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT | |
| VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT, |
| |
| VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF |
| } VmaAllocationCreateFlagBits; |
| typedef VkFlags VmaAllocationCreateFlags; |
| |
| typedef struct VmaAllocationCreateInfo |
| { |
| /// Use #VmaAllocationCreateFlagBits enum. |
| VmaAllocationCreateFlags flags; |
| /** \brief Intended usage of memory. |
| |
| You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n |
| If `pool` is not null, this member is ignored. |
| */ |
| VmaMemoryUsage usage; |
| /** \brief Flags that must be set in a Memory Type chosen for an allocation. |
| |
| Leave 0 if you specify memory requirements in other way. \n |
| If `pool` is not null, this member is ignored.*/ |
| VkMemoryPropertyFlags requiredFlags; |
| /** \brief Flags that preferably should be set in a memory type chosen for an allocation. |
| |
| Set to 0 if no additional flags are prefered. \n |
| If `pool` is not null, this member is ignored. */ |
| VkMemoryPropertyFlags preferredFlags; |
| /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. |
| |
| Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if |
| it meets other requirements specified by this structure, with no further |
| restrictions on memory type index. \n |
| If `pool` is not null, this member is ignored. |
| */ |
| uint32_t memoryTypeBits; |
| /** \brief Pool that this allocation should be created in. |
| |
| Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: |
| `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. |
| */ |
| VmaPool VMA_NULLABLE pool; |
| /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). |
| |
| If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either |
| null or pointer to a null-terminated string. The string will be then copied to |
| internal buffer, so it doesn't need to be valid after allocation call. |
| */ |
| void* VMA_NULLABLE pUserData; |
| } VmaAllocationCreateInfo; |
| |
| /** |
| \brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. |
| |
| This algorithm tries to find a memory type that: |
| |
| - Is allowed by memoryTypeBits. |
| - Contains all the flags from pAllocationCreateInfo->requiredFlags. |
| - Matches intended usage. |
| - Has as many flags from pAllocationCreateInfo->preferredFlags as possible. |
| |
| \return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result |
| from this function or any other allocating function probably means that your |
| device doesn't support any memory type with requested features for the specific |
| type of resource you want to use it for. Please check parameters of your |
| resource, like image layout (OPTIMAL versus LINEAR) or mip level count. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t memoryTypeBits, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, |
| uint32_t* VMA_NOT_NULL pMemoryTypeIndex); |
| |
| /** |
| \brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. |
| |
| It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. |
| It internally creates a temporary, dummy buffer that never has memory bound. |
| It is just a convenience function, equivalent to calling: |
| |
| - `vkCreateBuffer` |
| - `vkGetBufferMemoryRequirements` |
| - `vmaFindMemoryTypeIndex` |
| - `vkDestroyBuffer` |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, |
| uint32_t* VMA_NOT_NULL pMemoryTypeIndex); |
| |
| /** |
| \brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. |
| |
| It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. |
| It internally creates a temporary, dummy image that never has memory bound. |
| It is just a convenience function, equivalent to calling: |
| |
| - `vkCreateImage` |
| - `vkGetImageMemoryRequirements` |
| - `vmaFindMemoryTypeIndex` |
| - `vkDestroyImage` |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, |
| uint32_t* VMA_NOT_NULL pMemoryTypeIndex); |
| |
| /// Flags to be passed as VmaPoolCreateInfo::flags. |
| typedef enum VmaPoolCreateFlagBits { |
| /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. |
| |
| This is an optional optimization flag. |
| |
| If you always allocate using vmaCreateBuffer(), vmaCreateImage(), |
| vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator |
| knows exact type of your allocations so it can handle Buffer-Image Granularity |
| in the optimal way. |
| |
| If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), |
| exact type of such allocations is not known, so allocator must be conservative |
| in handling Buffer-Image Granularity, which can lead to suboptimal allocation |
| (wasted memory). In that case, if you can make sure you always allocate only |
| buffers and linear images or only optimal images out of this pool, use this flag |
| to make allocator disregard Buffer-Image Granularity and so make allocations |
| faster and more optimal. |
| */ |
| VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, |
| |
| /** \brief Enables alternative, linear allocation algorithm in this pool. |
| |
| Specify this flag to enable linear allocation algorithm, which always creates |
| new allocations after last one and doesn't reuse space from allocations freed in |
| between. It trades memory consumption for simplified algorithm and data |
| structure, which has better performance and uses less memory for metadata. |
| |
| By using this flag, you can achieve behavior of free-at-once, stack, |
| ring buffer, and double stack. For details, see documentation chapter |
| \ref linear_algorithm. |
| |
| When using this flag, you must specify VmaPoolCreateInfo::maxBlockCount == 1 (or 0 for default). |
| |
| For more details, see [Linear allocation algorithm](@ref linear_algorithm). |
| */ |
| VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, |
| |
| /** \brief Enables alternative, buddy allocation algorithm in this pool. |
| |
| It operates on a tree of blocks, each having size that is a power of two and |
| a half of its parent's size. Comparing to default algorithm, this one provides |
| faster allocation and deallocation and decreased external fragmentation, |
| at the expense of more memory wasted (internal fragmentation). |
| |
| For more details, see [Buddy allocation algorithm](@ref buddy_algorithm). |
| */ |
| VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT = 0x00000008, |
| |
| /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. |
| */ |
| VMA_POOL_CREATE_ALGORITHM_MASK = |
| VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT | |
| VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT, |
| |
| VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF |
| } VmaPoolCreateFlagBits; |
| typedef VkFlags VmaPoolCreateFlags; |
| |
| /** \brief Describes parameter of created #VmaPool. |
| */ |
| typedef struct VmaPoolCreateInfo { |
| /** \brief Vulkan memory type index to allocate this pool from. |
| */ |
| uint32_t memoryTypeIndex; |
| /** \brief Use combination of #VmaPoolCreateFlagBits. |
| */ |
| VmaPoolCreateFlags flags; |
| /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. |
| |
| Specify nonzero to set explicit, constant size of memory blocks used by this |
| pool. |
| |
| Leave 0 to use default and let the library manage block sizes automatically. |
| Sizes of particular blocks may vary. |
| */ |
| VkDeviceSize blockSize; |
| /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. |
| |
| Set to 0 to have no preallocated blocks and allow the pool be completely empty. |
| */ |
| size_t minBlockCount; |
| /** \brief Maximum number of blocks that can be allocated in this pool. Optional. |
| |
| Set to 0 to use default, which is `SIZE_MAX`, which means no limit. |
| |
| Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated |
| throughout whole lifetime of this pool. |
| */ |
| size_t maxBlockCount; |
| /** \brief Maximum number of additional frames that are in use at the same time as current frame. |
| |
| This value is used only when you make allocations with |
| #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become |
| lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount. |
| |
| For example, if you double-buffer your command buffers, so resources used for |
| rendering in previous frame may still be in use by the GPU at the moment you |
| allocate resources needed for the current frame, set this value to 1. |
| |
| If you want to allow any allocations other than used in the current frame to |
| become lost, set this value to 0. |
| */ |
| uint32_t frameInUseCount; |
| } VmaPoolCreateInfo; |
| |
| /** \brief Describes parameter of existing #VmaPool. |
| */ |
| typedef struct VmaPoolStats { |
| /** \brief Total amount of `VkDeviceMemory` allocated from Vulkan for this pool, in bytes. |
| */ |
| VkDeviceSize size; |
| /** \brief Total number of bytes in the pool not used by any #VmaAllocation. |
| */ |
| VkDeviceSize unusedSize; |
| /** \brief Number of #VmaAllocation objects created from this pool that were not destroyed or lost. |
| */ |
| size_t allocationCount; |
| /** \brief Number of continuous memory ranges in the pool not used by any #VmaAllocation. |
| */ |
| size_t unusedRangeCount; |
| /** \brief Size of the largest continuous free memory region available for new allocation. |
| |
| Making a new allocation of that size is not guaranteed to succeed because of |
| possible additional margin required to respect alignment and buffer/image |
| granularity. |
| */ |
| VkDeviceSize unusedRangeSizeMax; |
| /** \brief Number of `VkDeviceMemory` blocks allocated for this pool. |
| */ |
| size_t blockCount; |
| } VmaPoolStats; |
| |
| /** \brief Allocates Vulkan device memory and creates #VmaPool object. |
| |
| @param allocator Allocator object. |
| @param pCreateInfo Parameters of pool to create. |
| @param[out] pPool Handle to created pool. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, |
| VmaPool VMA_NULLABLE * VMA_NOT_NULL pPool); |
| |
| /** \brief Destroys #VmaPool object and frees Vulkan device memory. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaPool VMA_NULLABLE pool); |
| |
| /** \brief Retrieves statistics of existing #VmaPool object. |
| |
| @param allocator Allocator object. |
| @param pool Pool object. |
| @param[out] pPoolStats Statistics of specified pool. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaPool VMA_NOT_NULL pool, |
| VmaPoolStats* VMA_NOT_NULL pPoolStats); |
| |
| /** \brief Marks all allocations in given pool as lost if they are not used in current frame or VmaPoolCreateInfo::frameInUseCount back from now. |
| |
| @param allocator Allocator object. |
| @param pool Pool. |
| @param[out] pLostAllocationCount Number of allocations marked as lost. Optional - pass null if you don't need this information. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaPool VMA_NOT_NULL pool, |
| size_t* VMA_NULLABLE pLostAllocationCount); |
| |
| /** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. |
| |
| Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, |
| `VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is |
| `HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). |
| |
| Possible return values: |
| |
| - `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. |
| - `VK_SUCCESS` - corruption detection has been performed and succeeded. |
| - `VK_ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations. |
| `VMA_ASSERT` is also fired in that case. |
| - Other value: Error returned by Vulkan, e.g. memory mapping failure. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator VMA_NOT_NULL allocator, VmaPool VMA_NOT_NULL pool); |
| |
| /** \brief Retrieves name of a custom pool. |
| |
| After the call `ppName` is either null or points to an internally-owned null-terminated string |
| containing name of the pool that was previously set. The pointer becomes invalid when the pool is |
| destroyed or its name is changed using vmaSetPoolName(). |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaPool VMA_NOT_NULL pool, |
| const char* VMA_NULLABLE * VMA_NOT_NULL ppName); |
| |
| /** \brief Sets name of a custom pool. |
| |
| `pName` can be either null or pointer to a null-terminated string with new name for the pool. |
| Function makes internal copy of the string, so it can be changed or freed immediately after this call. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaPool VMA_NOT_NULL pool, |
| const char* VMA_NULLABLE pName); |
| |
| /** \struct VmaAllocation |
| \brief Represents single memory allocation. |
| |
| It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type |
| plus unique offset. |
| |
| There are multiple ways to create such object. |
| You need to fill structure VmaAllocationCreateInfo. |
| For more information see [Choosing memory type](@ref choosing_memory_type). |
| |
| Although the library provides convenience functions that create Vulkan buffer or image, |
| allocate memory for it and bind them together, |
| binding of the allocation to a buffer or an image is out of scope of the allocation itself. |
| Allocation object can exist without buffer/image bound, |
| binding can be done manually by the user, and destruction of it can be done |
| independently of destruction of the allocation. |
| |
| The object also remembers its size and some other information. |
| To retrieve this information, use function vmaGetAllocationInfo() and inspect |
| returned structure VmaAllocationInfo. |
| |
| Some kinds allocations can be in lost state. |
| For more information, see [Lost allocations](@ref lost_allocations). |
| */ |
| VK_DEFINE_HANDLE(VmaAllocation) |
| |
| /** \brief Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). |
| */ |
| typedef struct VmaAllocationInfo { |
| /** \brief Memory type index that this allocation was allocated from. |
| |
| It never changes. |
| */ |
| uint32_t memoryType; |
| /** \brief Handle to Vulkan memory object. |
| |
| Same memory object can be shared by multiple allocations. |
| |
| It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost. |
| |
| If the allocation is lost, it is equal to `VK_NULL_HANDLE`. |
| */ |
| VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; |
| /** \brief Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation. |
| |
| It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost. |
| */ |
| VkDeviceSize offset; |
| /** \brief Size of this allocation, in bytes. |
| |
| It never changes, unless allocation is lost. |
| */ |
| VkDeviceSize size; |
| /** \brief Pointer to the beginning of this allocation as mapped data. |
| |
| If the allocation hasn't been mapped using vmaMapMemory() and hasn't been |
| created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. |
| |
| It can change after call to vmaMapMemory(), vmaUnmapMemory(). |
| It can also change after call to vmaDefragment() if this allocation is passed to the function. |
| */ |
| void* VMA_NULLABLE pMappedData; |
| /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). |
| |
| It can change after call to vmaSetAllocationUserData() for this allocation. |
| */ |
| void* VMA_NULLABLE pUserData; |
| } VmaAllocationInfo; |
| |
| /** \brief General purpose memory allocation. |
| |
| @param[out] pAllocation Handle to allocated memory. |
| @param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). |
| |
| You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). |
| |
| It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), |
| vmaCreateBuffer(), vmaCreateImage() instead whenever possible. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, |
| VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation, |
| VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); |
| |
| /** \brief General purpose memory allocation for multiple allocation objects at once. |
| |
| @param allocator Allocator object. |
| @param pVkMemoryRequirements Memory requirements for each allocation. |
| @param pCreateInfo Creation parameters for each alloction. |
| @param allocationCount Number of allocations to make. |
| @param[out] pAllocations Pointer to array that will be filled with handles to created allocations. |
| @param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. |
| |
| You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). |
| |
| Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. |
| It is just a general purpose allocation function able to make multiple allocations at once. |
| It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. |
| |
| All allocations are made using same parameters. All of them are created out of the same memory pool and type. |
| If any allocation fails, all allocations already made within this function call are also freed, so that when |
| returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, |
| size_t allocationCount, |
| VmaAllocation VMA_NULLABLE * VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, |
| VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); |
| |
| /** |
| @param[out] pAllocation Handle to allocated memory. |
| @param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). |
| |
| You should free the memory using vmaFreeMemory(). |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, |
| VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation, |
| VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); |
| |
| /// Function similar to vmaAllocateMemoryForBuffer(). |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, |
| const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, |
| VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation, |
| VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); |
| |
| /** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). |
| |
| Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( |
| VmaAllocator VMA_NOT_NULL allocator, |
| const VmaAllocation VMA_NULLABLE allocation); |
| |
| /** \brief Frees memory and destroys multiple allocations. |
| |
| Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. |
| It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), |
| vmaAllocateMemoryPages() and other functions. |
| It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. |
| |
| Allocations in `pAllocations` array can come from any memory pools and types. |
| Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( |
| VmaAllocator VMA_NOT_NULL allocator, |
| size_t allocationCount, |
| const VmaAllocation VMA_NULLABLE * VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); |
| |
| /** \brief Deprecated. |
| |
| \deprecated |
| In version 2.2.0 it used to try to change allocation's size without moving or reallocating it. |
| In current version it returns `VK_SUCCESS` only if `newSize` equals current allocation's size. |
| Otherwise returns `VK_ERROR_OUT_OF_POOL_MEMORY`, indicating that allocation's size could not be changed. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeAllocation( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL 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`. |
| |
| This function also atomically "touches" allocation - marks it as used in current frame, |
| just like vmaTouchAllocation(). |
| If the allocation is in lost state, `pAllocationInfo->deviceMemory == VK_NULL_HANDLE`. |
| |
| Although this function uses atomics and doesn't lock any mutex, so it should be quite efficient, |
| you can avoid calling it too often. |
| |
| - You can retrieve same VmaAllocationInfo structure while creating your resource, from function |
| vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change |
| (e.g. due to defragmentation or allocation becoming lost). |
| - If you just want to check if allocation is not lost, vmaTouchAllocation() will work faster. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation, |
| VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); |
| |
| /** \brief Returns `VK_TRUE` if allocation is not lost and atomically marks it as used in current frame. |
| |
| If the allocation has been created with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, |
| this function returns `VK_TRUE` if it's not in lost state, so it can still be used. |
| It then also atomically "touches" the allocation - marks it as used in current frame, |
| so that you can be sure it won't become lost in current frame or next `frameInUseCount` frames. |
| |
| If the allocation is in lost state, the function returns `VK_FALSE`. |
| Memory of such allocation, as well as buffer or image bound to it, should not be used. |
| Lost allocation and the buffer/image still need to be destroyed. |
| |
| If the allocation has been created without #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, |
| this function always returns `VK_TRUE`. |
| */ |
| VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation); |
| |
| /** \brief Sets pUserData in given allocation to new value. |
| |
| If the allocation was created with VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT, |
| pUserData must be either null, or pointer to a null-terminated string. The function |
| makes local copy of the string and sets it as allocation's `pUserData`. String |
| passed as pUserData doesn't need to be valid for whole lifetime of the allocation - |
| you can free it after this call. String previously pointed by allocation's |
| pUserData is freed from memory. |
| |
| If the flag was not used, the value of pointer `pUserData` is just copied to |
| allocation's `pUserData`. It is opaque, so you can use it however you want - e.g. |
| as a pointer, ordinal number or some handle to you own data. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation, |
| void* VMA_NULLABLE pUserData); |
| |
| /** \brief Creates new allocation that is in lost state from the beginning. |
| |
| It can be useful if you need a dummy, non-null allocation. |
| |
| You still need to destroy created object using vmaFreeMemory(). |
| |
| Returned allocation is not tied to any specific memory pool or memory type and |
| not bound to any image or buffer. It has size = 0. It cannot be turned into |
| a real, non-empty allocation. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation); |
| |
| /** \brief Maps memory represented by given allocation and returns pointer to it. |
| |
| Maps memory represented by given allocation to make it accessible to CPU code. |
| When succeeded, `*ppData` contains pointer to first byte of this memory. |
| If the allocation is part of bigger `VkDeviceMemory` block, the pointer is |
| correctly offseted to the beginning of region assigned to this particular |
| allocation. |
| |
| Mapping is internally reference-counted and synchronized, so despite raw Vulkan |
| function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` |
| multiple times simultaneously, it is safe to call this function on allocations |
| assigned to the same memory block. Actual Vulkan memory will be mapped on first |
| mapping and unmapped on last unmapping. |
| |
| If the function succeeded, you must call vmaUnmapMemory() to unmap the |
| allocation when mapping is no longer needed or before freeing the allocation, at |
| the latest. |
| |
| It also safe to call this function multiple times on the same allocation. You |
| must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). |
| |
| It is also safe to call this function on allocation created with |
| #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. |
| You must still call vmaUnmapMemory() same number of times as you called |
| vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the |
| "0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. |
| |
| This function fails when used on allocation made in memory type that is not |
| `HOST_VISIBLE`. |
| |
| This function always fails when called for allocation that was created with |
| #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocations cannot be |
| mapped. |
| |
| This function doesn't automatically flush or invalidate caches. |
| If the allocation is made from a memory types that is not `HOST_COHERENT`, |
| you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation, |
| void* VMA_NULLABLE * VMA_NOT_NULL ppData); |
| |
| /** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). |
| |
| For details, see description of vmaMapMemory(). |
| |
| This function doesn't automatically flush or invalidate caches. |
| If the allocation is made from a memory types that is not `HOST_COHERENT`, |
| you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. |
| */ |
| VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation); |
| |
| /** \brief Flushes memory of given allocation. |
| |
| Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. |
| It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. |
| Unmap operation doesn't do that automatically. |
| |
| - `offset` must be relative to the beginning of allocation. |
| - `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. |
| - `offset` and `size` don't have to be aligned. |
| They are internally rounded down/up to multiply of `nonCoherentAtomSize`. |
| - If `size` is 0, this call is ignored. |
| - If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, |
| this call is ignored. |
| |
| Warning! `offset` and `size` are relative to the contents of given `allocation`. |
| If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. |
| Do not pass allocation's offset as `offset`!!! |
| |
| This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is |
| called, otherwise `VK_SUCCESS`. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation, |
| VkDeviceSize offset, |
| VkDeviceSize size); |
| |
| /** \brief Invalidates memory of given allocation. |
| |
| Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. |
| It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. |
| Map operation doesn't do that automatically. |
| |
| - `offset` must be relative to the beginning of allocation. |
| - `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. |
| - `offset` and `size` don't have to be aligned. |
| They are internally rounded down/up to multiply of `nonCoherentAtomSize`. |
| - If `size` is 0, this call is ignored. |
| - If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, |
| this call is ignored. |
| |
| Warning! `offset` and `size` are relative to the contents of given `allocation`. |
| If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. |
| Do not pass allocation's offset as `offset`!!! |
| |
| This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if |
| it is called, otherwise `VK_SUCCESS`. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( |
| VmaAllocator VMA_NOT_NULL allocator, |
| VmaAllocation VMA_NOT_NULL allocation, |
| VkDeviceSize offset, |
| VkDeviceSize size); |
| |
| /** \brief Flushes memory of given set of allocations. |
| |
| Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. |
| For more information, see documentation of vmaFlushAllocation(). |
| |
| \param allocator |
| \param allocationCount |
| \param allocations |
| \param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. |
| \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. |
| |
| This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is |
| called, otherwise `VK_SUCCESS`. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t allocationCount, |
| const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, |
| const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, |
| const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); |
| |
| /** \brief Invalidates memory of given set of allocations. |
| |
| Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. |
| For more information, see documentation of vmaInvalidateAllocation(). |
| |
| \param allocator |
| \param allocationCount |
| \param allocations |
| \param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. |
| \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. |
| |
| This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is |
| called, otherwise `VK_SUCCESS`. |
| */ |
| VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( |
| VmaAllocator VMA_NOT_NULL allocator, |
| uint32_t allocationCount, |
| const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, |
| const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, |
| const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); |
| |
| /** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. |
| |