Version 1.0.1 (2017-07-04)
Members grouped: see Modules.
All members: see vk_mem_alloc.h.
Problem Statement
Memory allocation and resource (buffer and image) creation in Vulkan is difficult (comparing to older graphics API-s, like D3D11 or OpenGL) for several reasons:
- It requires a lot of boilerplate code, just like everything else in Vulkan, because it is a low-level and high-performance API.
- There is additional level of indirection: VkDeviceMemory is allocated separately from creating VkBuffer/VkImage and they must be bound together. The binding cannot be changed later - resource must be recreated.
- Driver must be queried for supported memory heaps and memory types. Different IHV-s provide different types of it.
- Resources that don't fit in VRAM are not automatically evicted to RAM. Developer must handle out-of-memory errors on his own.
- It is recommended practice to allocate bigger chunks of memory and assign parts of them to particular resources.
Features
This library is helps game developers to manage memory allocations and resource creation by offering some higher-level functions. Features of the library could be divided into several layers, low level to high level:
- Functions that help to choose correct and optimal memory type based on intended usage of the memory.
- Required or preferred traits of the memory are expressed using higher-level description comparing to Vulkan flags.
- Functions that allocate memory blocks, reserve and return parts of them (VkDeviceMemory + offset + size) to the user.
- Library keeps track of allocated memory blocks, used and unused ranges inside them, finds best matching unused ranges for new allocations, takes all the rules of alignment into consideration.
- Functions that can create an image/buffer, allocate memory for it and bind them together - all in one call.
Prequisites
- Self-contained C++ library in single header file. No external dependencies other than standard C and C++ library and of course Vulkan.
- Public interface in C, in same convention as Vulkan API. Implementation in C++.
- Interface documented using Doxygen-style comments.
- Platform-independent, but developed and tested on Windows using Visual Studio.
- Error handling implemented by returning VkResult error codes - same way as in Vulkan.
Quick Start
In your project code:
- Include "vk_mem_alloc.h" file wherever you want to use the library.
- In exacly one C++ file define following macro before include to build library implementation.
#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"
At program startup:
- Initialize Vulkan to have VkPhysicalDevice and VkDevice object.
- Fill VmaAllocatorCreateInfo structure and create VmaAllocator object by calling vmaCreateAllocator().
VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.physicalDevice = physicalDevice;
allocatorInfo.device = device;
VmaAllocator allocator;
vmaCreateAllocator(&allocatorInfo, &allocator);
When you want to create a buffer or image:
- Fill VkBufferCreateInfo / VkImageCreateInfo structure.
- Fill VmaMemoryRequirements structure.
- Call vmaCreateBuffer() / vmaCreateImage() to get VkBuffer/VkImage with memory already allocated and bound to it.
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = myBufferSize;
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VmaMemoryRequirements memReq = {};
memReq.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VkBuffer buffer;
vmaCreateBuffer(allocator, &bufferInfo, &memReq, &buffer, nullptr, nullptr);
When no longer needed, destroy your buffer or image using vmaDestroyBuffer() / vmaDestroyImage(). This function would also free memory bound to it.
vmaDestroyBuffer(allocator, buffer);
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 etc. C++ STL is used by default, but changing these allows you to get rid of any STL usage if you want, as many game developers tend to do.
Custom memory allocator
You can use custom memory allocator 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.
Thread safety
All calls to functions that take VmaAllocator as first parameter are safe to call from multiple threads simultaneously, synchronized internally when needed.