Open 3D Engine Atom Gem API Reference  24.09
O3DE is an open-source, fully-featured, high-fidelity, modular 3D engine for building games and simulations, available to every industry.
Configuration

Please check file D3D12MemAlloc.cpp lines between "Configuration Begin" and "Configuration End" to find macros that you can define to change the behavior of the library, primarily for debugging purposes.

Custom CPU memory allocator

If you use custom allocator for CPU memory rather than default C++ operator new and delete or malloc and free functions, you can make this library using your allocator as well by filling structure D3D12MA::ALLOCATION_CALLBACKS and passing it as optional member D3D12MA::ALLOCATOR_DESC::pAllocationCallbacks. Functions pointed there will be used by the library to make any CPU-side allocations. Example:

#include <malloc.h>
void* CustomAllocate(size_t Size, size_t Alignment, void* pPrivateData)
{
void* memory = _aligned_malloc(Size, Alignment);
// Your extra bookkeeping here...
return memory;
}
void CustomFree(void* pMemory, void* pPrivateData)
{
// Your extra bookkeeping here...
_aligned_free(pMemory);
}
(...)
D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};
allocationCallbacks.pAllocate = &CustomAllocate;
allocationCallbacks.pFree = &CustomFree;
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
allocatorDesc.pDevice = device;
allocatorDesc.pAdapter = adapter;
allocatorDesc.pAllocationCallbacks = &allocationCallbacks;
D3D12MA::Allocator* allocator;
HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
Represents main object of this library initialized for particular ID3D12Device.
Definition: D3D12MemAlloc.h:1068
Custom callbacks to CPU memory allocation functions.
Definition: D3D12MemAlloc.h:188
FREE_FUNC_PTR pFree
Dellocation function.
Definition: D3D12MemAlloc.h:192
ALLOCATE_FUNC_PTR pAllocate
Allocation function.
Definition: D3D12MemAlloc.h:190
Parameters of created Allocator object. To be used with CreateAllocator().
Definition: D3D12MemAlloc.h:1029
const ALLOCATION_CALLBACKS * pAllocationCallbacks
Custom CPU memory allocation callbacks. Optional.
Definition: D3D12MemAlloc.h:1049
IDXGIAdapter * pAdapter
Definition: D3D12MemAlloc.h:1055
ID3D12Device * pDevice
Definition: D3D12MemAlloc.h:1037

Debug margins

By default, allocations are laid out in memory blocks next to each other if possible (considering required alignment returned by ID3D12Device::GetResourceAllocationInfo).

Allocations without margin

Define macro D3D12MA_DEBUG_MARGIN to some non-zero value (e.g. 16) inside "D3D12MemAlloc.cpp" to enforce specified number of bytes as a margin after every allocation.

Allocations with margin

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.

Margins work with all memory heap types.

Margin is applied only to placed allocations made out of memory heaps and not to committed allocations, which have their own, implicit memory heap of specific size. It is thus not applied to allocations made using D3D12MA::ALLOCATION_FLAG_COMMITTED flag or those automatically decided to put into committed allocations, e.g. due to its large size.

Margins appear in JSON dump as part of free space.

Note that enabling margins increases memory usage and fragmentation.

Margins do not apply to Virtual allocator.

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.

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:

m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory;

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.

Third, VMA tries to fetch remaining pointers that are still null by calling vkGetInstanceProcAddr and vkGetDeviceProcAddr on its own. You need to only fill in VmaVulkanFunctions::vkGetInstanceProcAddr and VmaVulkanFunctions::vkGetDeviceProcAddr. Other pointers will be fetched automatically. 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.

Custom CPU 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.

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.

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-dependent - 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.