Vulkan Memory Allocator
Quick start

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:

  1. 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.
  2. In exactly one CPP file define following macro before this include. It enables also internal definitions.
#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"

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.

You may need to configure the way you import Vulkan functions.

  • By default, VMA assumes you you link statically with Vulkan API. If this is not the case, #define VMA_STATIC_VULKAN_FUNCTIONS 0 before #include of the VMA implementation and use another way.
  • You can #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 and pass only pointers to vkGetInstanceProcAddr and vkGetDeviceProcAddr functions through VmaAllocatorCreateInfo::pVulkanFunctions. All the remaining Vulkan functions will be fetched automatically.
  • Finally, you can provide your own pointers to all Vulkan functions needed by VMA using structure member VmaAllocatorCreateInfo::pVulkanFunctions, if you fetched them in some custom way e.g. using some loader like Volk.

Initialization

At program startup:

  1. Initialize Vulkan to have VkPhysicalDevice, VkDevice and VkInstance object.
  2. Fill VmaAllocatorCreateInfo structure and create VmaAllocator object by calling vmaCreateAllocator().
VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2;
allocatorInfo.physicalDevice = physicalDevice;
allocatorInfo.device = device;
allocatorInfo.instance = instance;
VmaAllocator allocator;
vmaCreateAllocator(&allocatorInfo, &allocator);
VkResult vmaCreateAllocator(const VmaAllocatorCreateInfo *pCreateInfo, VmaAllocator *pAllocator)
Creates VmaAllocator object.
Description of a Allocator to be created.
Definition: vk_mem_alloc.h:944
VkPhysicalDevice physicalDevice
Vulkan physical device.
Definition: vk_mem_alloc.h:949
VkInstance instance
Handle to Vulkan instance object.
Definition: vk_mem_alloc.h:997
VkDevice device
Vulkan device.
Definition: vk_mem_alloc.h:952
uint32_t vulkanApiVersion
Optional. The highest version of Vulkan that the application is designed to use.
Definition: vk_mem_alloc.h:1006
Represents main object of this library initialized.

Only members physicalDevice, device, instance are required. However, you should inform the library which Vulkan version do you use by setting VmaAllocatorCreateInfo::vulkanApiVersion and which extensions did you enable by setting VmaAllocatorCreateInfo::flags (like VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT for VK_KHR_buffer_device_address). Otherwise, VMA would use only features of Vulkan 1.0 core with no extensions.

Resource allocation

When you want to create a buffer or image:

  1. Fill VkBufferCreateInfo / VkImageCreateInfo structure.
  2. Fill VmaAllocationCreateInfo structure.
  3. 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 = 65536;
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VmaAllocationCreateInfo allocInfo = {};
VkBuffer buffer;
VmaAllocation allocation;
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
VkResult vmaCreateBuffer(VmaAllocator allocator, const VkBufferCreateInfo *pBufferCreateInfo, const VmaAllocationCreateInfo *pAllocationCreateInfo, VkBuffer *pBuffer, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
@ VMA_MEMORY_USAGE_GPU_ONLY
Definition: vk_mem_alloc.h:466
Definition: vk_mem_alloc.h:1118
VmaMemoryUsage usage
Intended usage of memory.
Definition: vk_mem_alloc.h:1126
Represents single memory allocation.

Don't forget to destroy your objects when no longer needed:

vmaDestroyBuffer(allocator, buffer, allocation);
void vmaDestroyBuffer(VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)
Destroys Vulkan buffer and frees allocated memory.
void vmaDestroyAllocator(VmaAllocator allocator)
Destroys allocator object.