Path: blob/master/thirdparty/d3d12ma/D3D12MemAlloc.h
22071 views
//1// Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved.2//3// Permission is hereby granted, free of charge, to any person obtaining a copy4// of this software and associated documentation files (the "Software"), to deal5// in the Software without restriction, including without limitation the rights6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell7// copies of the Software, and to permit persons to whom the Software is8// furnished to do so, subject to the following conditions:9//10// The above copyright notice and this permission notice shall be included in11// all copies or substantial portions of the Software.12//13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN19// THE SOFTWARE.20//2122#pragma once2324/** \mainpage D3D12 Memory Allocator2526<b>Version 2.1.0-development</b> (2024-07-05)2728Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. \n29License: MIT3031Documentation of all members: D3D12MemAlloc.h3233\section main_table_of_contents Table of contents3435- \subpage quick_start36- [Project setup](@ref quick_start_project_setup)37- [Creating resources](@ref quick_start_creating_resources)38- [Resource reference counting](@ref quick_start_resource_reference_counting)39- [Mapping memory](@ref quick_start_mapping_memory)40- [Helper structures](@ref quick_start_helper_structures)41- \subpage custom_pools42- \subpage optimal_allocation43- [Avoiding running out of memory](@ref optimal_allocation_avoiding_running_out_of_memory)44- [Allocation performance](@ref optimal_allocation_allocation_Performance)45- [Sub-allocating buffers](@ref optimal_allocation_suballocating_buffers)46- [Residency priority](@ref optimal_allocation_residency_priority)47- [GPU upload heap](@ref optimal_allocation_gpu_upload_heap)48- [Committed versus placed resources](@ref optimal_allocation_committed_vs_placed)49- [Resource alignment](@ref optimal_allocation_resource_alignment)50- \subpage defragmentation51- \subpage statistics52- \subpage resource_aliasing53- \subpage linear_algorithm54- \subpage virtual_allocator55- \subpage configuration56- [Custom CPU memory allocator](@ref custom_memory_allocator)57- [Debug margins](@ref debug_margins)58- \subpage general_considerations59- [Thread safety](@ref general_considerations_thread_safety)60- [Versioning and compatibility](@ref general_considerations_versioning_and_compatibility)61- [Features not supported](@ref general_considerations_features_not_supported)6263\section main_see_also Web links6465- [Direct3D 12 Memory Allocator at GPUOpen.com](https://gpuopen.com/gaming-product/d3d12-memory-allocator/) - product page66- [GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator at GitHub.com](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator) - source code repository67*/6869// If using this library on a platform different than Windows PC or want to use different version of DXGI,70// you should include D3D12-compatible headers before this library on your own and define71// D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED.72// Alternatively, if you are targeting the open sourced DirectX headers, defining D3D12MA_USING_DIRECTX_HEADERS73// will include them rather the ones provided by the Windows SDK.74#ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED75#if defined(D3D12MA_USING_DIRECTX_HEADERS)76#include <directx/d3d12.h>77#include <dxguids/dxguids.h>78#else79#include <d3d12.h>80#endif8182#include <dxgi1_4.h>83#endif8485#ifndef D3D12MA_DXGI_1_486#ifdef __IDXGIAdapter3_INTERFACE_DEFINED__87/// Define this macro to 0 to disable usage of DXGI 1.4 (which is used for `IDXGIAdapter3` and query for memory budget).88#define D3D12MA_DXGI_1_4 189#else90#define D3D12MA_DXGI_1_4 091#endif92#endif9394#ifndef D3D12MA_CREATE_NOT_ZEROED_AVAILABLE95#ifdef __ID3D12Device8_INTERFACE_DEFINED__96/// This macro is defined to 0 or 1 automatically. Define it to 0 to disable support for `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED`.97#define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 198#else99#define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 0100#endif101#endif102103#ifndef D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT104/** \brief105When defined to value other than 0, the library will try to use106`D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT` or `D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT`107for created textures when possible, which can save memory because some small textures108may get their alignment 4 KB and their size a multiply of 4 KB instead of 64 KB.109110- `#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 0` -111Disables small texture alignment.112- `#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1` (the default) -113Enables conservative algorithm that will use small alignment only for some textures114that are surely known to support it.115- `#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 2` -116Enables query for small alignment to D3D12 (based on Microsoft sample) which will117enable small alignment for more textures, but will also generate D3D Debug Layer118error #721 on call to `ID3D12Device::GetResourceAllocationInfo`, which you should just119ignore.120*/121#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1122#endif123124#ifndef D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS125/// Set of flags recommended for use in D3D12MA::ALLOCATOR_DESC::Flags for optimal performance.126#define D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS (ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED)127#endif128129#ifndef D3D12MA_RECOMMENDED_HEAP_FLAGS130#if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE131#define D3D12MA_RECOMMENDED_HEAP_FLAGS (D3D12_HEAP_FLAG_CREATE_NOT_ZEROED)132#else133/// Set of flags recommended for use in D3D12MA::POOL_DESC::HeapFlags for optimal performance.134#define D3D12MA_RECOMMENDED_HEAP_FLAGS (D3D12_HEAP_FLAG_NONE)135#endif136#endif137138#ifndef D3D12MA_RECOMMENDED_POOL_FLAGS139/// Set of flags recommended for use in D3D12MA::POOL_DESC::Flags for optimal performance.140#define D3D12MA_RECOMMENDED_POOL_FLAGS (POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED)141#endif142143144/// \cond INTERNAL145146#define D3D12MA_CLASS_NO_COPY(className) \147private: \148className(const className&) = delete; \149className(className&&) = delete; \150className& operator=(const className&) = delete; \151className& operator=(className&&) = delete;152153// To be used with MAKE_HRESULT to define custom error codes.154#define FACILITY_D3D12MA 3542155156/*157If providing your own implementation, you need to implement a subset of std::atomic.158*/159#if !defined(D3D12MA_ATOMIC_UINT32) || !defined(D3D12MA_ATOMIC_UINT64)160#include <atomic>161#endif162163#ifndef D3D12MA_ATOMIC_UINT32164#define D3D12MA_ATOMIC_UINT32 std::atomic<UINT>165#endif166167#ifndef D3D12MA_ATOMIC_UINT64168#define D3D12MA_ATOMIC_UINT64 std::atomic<UINT64>169#endif170171#ifdef D3D12MA_EXPORTS172#define D3D12MA_API __declspec(dllexport)173#elif defined(D3D12MA_IMPORTS)174#define D3D12MA_API __declspec(dllimport)175#else176#define D3D12MA_API177#endif178179// Forward declaration if ID3D12ProtectedResourceSession is not defined inside the headers (older SDK, pre ID3D12Device4)180struct ID3D12ProtectedResourceSession;181182// Define this enum even if SDK doesn't provide it, to simplify the API.183#ifndef __ID3D12Device1_INTERFACE_DEFINED__184typedef enum D3D12_RESIDENCY_PRIORITY185{186D3D12_RESIDENCY_PRIORITY_MINIMUM = 0x28000000,187D3D12_RESIDENCY_PRIORITY_LOW = 0x50000000,188D3D12_RESIDENCY_PRIORITY_NORMAL = 0x78000000,189D3D12_RESIDENCY_PRIORITY_HIGH = 0xa0010000,190D3D12_RESIDENCY_PRIORITY_MAXIMUM = 0xc8000000191} D3D12_RESIDENCY_PRIORITY;192#endif193194namespace D3D12MA195{196class D3D12MA_API IUnknownImpl : public IUnknown197{198public:199virtual ~IUnknownImpl() = default;200HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override;201ULONG STDMETHODCALLTYPE AddRef() override;202ULONG STDMETHODCALLTYPE Release() override;203protected:204virtual void ReleaseThis() { delete this; }205private:206D3D12MA_ATOMIC_UINT32 m_RefCount = {1};207};208} // namespace D3D12MA209210/// \endcond211212namespace D3D12MA213{214215/// \cond INTERNAL216class DefragmentationContextPimpl;217class AllocatorPimpl;218class PoolPimpl;219class NormalBlock;220class BlockVector;221class CommittedAllocationList;222class JsonWriter;223class VirtualBlockPimpl;224/// \endcond225226class Pool;227class Allocator;228struct Statistics;229struct DetailedStatistics;230struct TotalStatistics;231232/// \brief Unique identifier of single allocation done inside the memory heap.233typedef UINT64 AllocHandle;234235/// Pointer to custom callback function that allocates CPU memory.236using ALLOCATE_FUNC_PTR = void* (*)(size_t Size, size_t Alignment, void* pPrivateData);237/**238\brief Pointer to custom callback function that deallocates CPU memory.239240`pMemory = null` should be accepted and ignored.241*/242using FREE_FUNC_PTR = void (*)(void* pMemory, void* pPrivateData);243244/// Custom callbacks to CPU memory allocation functions.245struct ALLOCATION_CALLBACKS246{247/// %Allocation function.248ALLOCATE_FUNC_PTR pAllocate;249/// Dellocation function.250FREE_FUNC_PTR pFree;251/// Custom data that will be passed to allocation and deallocation functions as `pUserData` parameter.252void* pPrivateData;253};254255256/// \brief Bit flags to be used with ALLOCATION_DESC::Flags.257enum ALLOCATION_FLAGS258{259/// Zero260ALLOCATION_FLAG_NONE = 0,261262/**263Set this flag if the allocation should have its own dedicated memory allocation (committed resource with implicit heap).264265Use it for special, big resources, like fullscreen textures used as render targets.266267- When used with functions like D3D12MA::Allocator::CreateResource, it will use `ID3D12Device::CreateCommittedResource`,268so the created allocation will contain a resource (D3D12MA::Allocation::GetResource() `!= NULL`) but will not have269a heap (D3D12MA::Allocation::GetHeap() `== NULL`), as the heap is implicit.270- When used with raw memory allocation like D3D12MA::Allocator::AllocateMemory, it will use `ID3D12Device::CreateHeap`,271so the created allocation will contain a heap (D3D12MA::Allocation::GetHeap() `!= NULL`) and its offset will always be 0.272*/273ALLOCATION_FLAG_COMMITTED = 0x1,274275/**276Set this flag to only try to allocate from existing memory heaps and never create new such heap.277278If new allocation cannot be placed in any of the existing heaps, allocation279fails with `E_OUTOFMEMORY` error.280281You should not use D3D12MA::ALLOCATION_FLAG_COMMITTED and282D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.283*/284ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2,285286/** Create allocation only if additional memory required for it, if any, won't exceed287memory budget. Otherwise return `E_OUTOFMEMORY`.288*/289ALLOCATION_FLAG_WITHIN_BUDGET = 0x4,290291/** Allocation will be created from upper stack in a double stack pool.292293This flag is only allowed for custom pools created with #POOL_FLAG_ALGORITHM_LINEAR flag.294*/295ALLOCATION_FLAG_UPPER_ADDRESS = 0x8,296297/** Set this flag if the allocated memory will have aliasing resources.298299Use this when calling D3D12MA::Allocator::CreateResource() and similar to300guarantee creation of explicit heap for desired allocation and prevent it from using `CreateCommittedResource`,301so that new allocation object will always have `allocation->GetHeap() != NULL`.302*/303ALLOCATION_FLAG_CAN_ALIAS = 0x10,304305/** %Allocation strategy that chooses smallest possible free range for the allocation306to minimize memory usage and fragmentation, possibly at the expense of allocation time.307*/308ALLOCATION_FLAG_STRATEGY_MIN_MEMORY = 0x00010000,309310/** %Allocation strategy that chooses first suitable free range for the allocation -311not necessarily in terms of the smallest offset but the one that is easiest and fastest to find312to minimize allocation time, possibly at the expense of allocation quality.313*/314ALLOCATION_FLAG_STRATEGY_MIN_TIME = 0x00020000,315316/** %Allocation strategy that chooses always the lowest offset in available space.317This is not the most efficient strategy but achieves highly packed data.318Used internally by defragmentation, not recomended in typical usage.319*/320ALLOCATION_FLAG_STRATEGY_MIN_OFFSET = 0x0004000,321322/// Alias to #ALLOCATION_FLAG_STRATEGY_MIN_MEMORY.323ALLOCATION_FLAG_STRATEGY_BEST_FIT = ALLOCATION_FLAG_STRATEGY_MIN_MEMORY,324/// Alias to #ALLOCATION_FLAG_STRATEGY_MIN_TIME.325ALLOCATION_FLAG_STRATEGY_FIRST_FIT = ALLOCATION_FLAG_STRATEGY_MIN_TIME,326327/// A bit mask to extract only `STRATEGY` bits from entire set of flags.328ALLOCATION_FLAG_STRATEGY_MASK =329ALLOCATION_FLAG_STRATEGY_MIN_MEMORY |330ALLOCATION_FLAG_STRATEGY_MIN_TIME |331ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,332};333334/// \brief Parameters of created D3D12MA::Allocation object. To be used with Allocator::CreateResource.335struct ALLOCATION_DESC336{337/// Flags for the allocation.338ALLOCATION_FLAGS Flags;339/** \brief The type of memory heap where the new allocation should be placed.340341It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.342343When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.344*/345D3D12_HEAP_TYPE HeapType;346/** \brief Additional heap flags to be used when allocating memory.347348In most cases it can be 0.349350- If you use D3D12MA::Allocator::CreateResource(), you don't need to care.351Necessary flag `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`, `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,352or `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES` is added automatically.353- If you use D3D12MA::Allocator::AllocateMemory(), you should specify one of those `ALLOW_ONLY` flags.354Except when you validate that D3D12MA::Allocator::GetD3D12Options()`.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1` -355then you can leave it 0.356- You can specify additional flags if needed. Then the memory will always be allocated as357separate block using `D3D12Device::CreateCommittedResource` or `CreateHeap`, not as part of an existing larget block.358359When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.360*/361D3D12_HEAP_FLAGS ExtraHeapFlags;362/** \brief Custom pool to place the new resource in. Optional.363364When not null, the resource will be created inside specified custom pool.365Members `HeapType`, `ExtraHeapFlags` are then ignored.366*/367Pool* CustomPool;368/// Custom general-purpose pointer that will be stored in D3D12MA::Allocation.369void* pPrivateData;370};371372/** \brief Calculated statistics of memory usage e.g. in a specific memory heap type,373memory segment group, custom pool, or total.374375These are fast to calculate.376See functions: D3D12MA::Allocator::GetBudget(), D3D12MA::Pool::GetStatistics().377*/378struct Statistics379{380/** \brief Number of D3D12 memory blocks allocated - `ID3D12Heap` objects and committed resources.381*/382UINT BlockCount;383/** \brief Number of D3D12MA::Allocation objects allocated.384385Committed allocations have their own blocks, so each one adds 1 to `AllocationCount` as well as `BlockCount`.386*/387UINT AllocationCount;388/** \brief Number of bytes allocated in memory blocks.389*/390UINT64 BlockBytes;391/** \brief Total number of bytes occupied by all D3D12MA::Allocation objects.392393Always less or equal than `BlockBytes`.394Difference `(BlockBytes - AllocationBytes)` is the amount of memory allocated from D3D12395but unused by any D3D12MA::Allocation.396*/397UINT64 AllocationBytes;398};399400/** \brief More detailed statistics than D3D12MA::Statistics.401402These are slower to calculate. Use for debugging purposes.403See functions: D3D12MA::Allocator::CalculateStatistics(), D3D12MA::Pool::CalculateStatistics().404405Averages are not provided because they can be easily calculated as:406407\code408UINT64 AllocationSizeAvg = DetailedStats.Statistics.AllocationBytes / detailedStats.Statistics.AllocationCount;409UINT64 UnusedBytes = DetailedStats.Statistics.BlockBytes - DetailedStats.Statistics.AllocationBytes;410UINT64 UnusedRangeSizeAvg = UnusedBytes / DetailedStats.UnusedRangeCount;411\endcode412*/413struct DetailedStatistics414{415/// Basic statistics.416Statistics Stats;417/// Number of free ranges of memory between allocations.418UINT UnusedRangeCount;419/// Smallest allocation size. `UINT64_MAX` if there are 0 allocations.420UINT64 AllocationSizeMin;421/// Largest allocation size. 0 if there are 0 allocations.422UINT64 AllocationSizeMax;423/// Smallest empty range size. `UINT64_MAX` if there are 0 empty ranges.424UINT64 UnusedRangeSizeMin;425/// Largest empty range size. 0 if there are 0 empty ranges.426UINT64 UnusedRangeSizeMax;427};428429/** \brief General statistics from current state of the allocator -430total memory usage across all memory heaps and segments.431432These are slower to calculate. Use for debugging purposes.433See function D3D12MA::Allocator::CalculateStatistics().434*/435struct TotalStatistics436{437/** \brief One element for each type of heap located at the following indices:438439- 0 = `D3D12_HEAP_TYPE_DEFAULT`440- 1 = `D3D12_HEAP_TYPE_UPLOAD`441- 2 = `D3D12_HEAP_TYPE_READBACK`442- 3 = `D3D12_HEAP_TYPE_CUSTOM`443- 4 = `D3D12_HEAP_TYPE_GPU_UPLOAD`444*/445DetailedStatistics HeapType[5];446/** \brief One element for each memory segment group located at the following indices:447448- 0 = `DXGI_MEMORY_SEGMENT_GROUP_LOCAL`449- 1 = `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`450451Meaning of these segment groups is:452453- When `IsUMA() == FALSE` (discrete graphics card):454- `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` (index 0) represents GPU memory455(resources allocated in `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_GPU_UPLOAD` or `D3D12_MEMORY_POOL_L1`).456- `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL` (index 1) represents system memory457(resources allocated in `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`, or `D3D12_MEMORY_POOL_L0`).458- When `IsUMA() == TRUE` (integrated graphics chip):459- `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` = (index 0) represents memory shared for all the resources.460- `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL` = (index 1) is unused and always 0.461*/462DetailedStatistics MemorySegmentGroup[2];463/// Total statistics from all memory allocated from D3D12.464DetailedStatistics Total;465};466467/** \brief %Statistics of current memory usage and available budget for a specific memory segment group.468469These are fast to calculate. See function D3D12MA::Allocator::GetBudget().470*/471struct Budget472{473/** \brief %Statistics fetched from the library.474*/475Statistics Stats;476/** \brief Estimated current memory usage of the program.477478Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if possible.479480It might be different than `BlockBytes` (usually higher) due to additional implicit objects481also occupying the memory, like swapchain, pipeline state objects, descriptor heaps, command lists, or482heaps and resources allocated outside of this library, if any.483*/484UINT64 UsageBytes;485/** \brief Estimated amount of memory available to the program.486487Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if possible.488489It might be different (most probably smaller) than memory capacity returned490by D3D12MA::Allocator::GetMemoryCapacity() due to factors491external to the program, decided by the operating system.492Difference `BudgetBytes - UsageBytes` is the amount of additional memory that can probably493be allocated without problems. Exceeding the budget may result in various problems.494*/495UINT64 BudgetBytes;496};497498499/// \brief Represents single memory allocation done inside VirtualBlock.500struct D3D12MA_API VirtualAllocation501{502/// \brief Unique idenitfier of current allocation. 0 means null/invalid.503AllocHandle AllocHandle;504};505506/** \brief Represents single memory allocation.507508It may be either implicit memory heap dedicated to a single resource or a509specific region of a bigger heap plus unique offset.510511To create such object, fill structure D3D12MA::ALLOCATION_DESC and call function512Allocator::CreateResource.513514The object remembers size and some other information.515To retrieve this information, use methods of this class.516517The object also remembers `ID3D12Resource` and "owns" a reference to it,518so it calls `%Release()` on the resource when destroyed.519*/520class D3D12MA_API Allocation : public IUnknownImpl521{522public:523/** \brief Returns offset in bytes from the start of memory heap.524525You usually don't need to use this offset. If you create a buffer or a texture together with the allocation using function526D3D12MA::Allocator::CreateResource, functions that operate on that resource refer to the beginning of the resource,527not entire memory heap.528529If the Allocation represents committed resource with implicit heap, returns 0.530*/531UINT64 GetOffset() const;532533/// Returns alignment that resource was created with.534UINT64 GetAlignment() const { return m_Alignment; }535536/** \brief Returns size in bytes of the allocation.537538- If you created a buffer or a texture together with the allocation using function D3D12MA::Allocator::CreateResource,539this is the size of the resource returned by `ID3D12Device::GetResourceAllocationInfo`.540- For allocations made out of bigger memory blocks, this also is the size of the memory region assigned exclusively to this allocation.541- For resources created as committed, this value may not be accurate. DirectX implementation may optimize memory usage internally542so that you may even observe regions of `ID3D12Resource::GetGPUVirtualAddress()` + Allocation::GetSize() to overlap in memory and still work correctly.543*/544UINT64 GetSize() const { return m_Size; }545546/** \brief Returns D3D12 resource associated with this object.547548Calling this method doesn't increment resource's reference counter.549*/550ID3D12Resource* GetResource() const { return m_Resource; }551552/** \brief Releases the resource currently pointed by the allocation (if not null), sets it to new one, incrementing its reference counter (if not null).553554\warning555This is an advanced feature that should be used only in special cases, e.g. during \subpage defragmentation.556Typically, an allocation object should reference the resource that was created together with it.557If you swap it to another resource of different size, \subpage statistics and budgets can be calculated incorrectly.558*/559void SetResource(ID3D12Resource* pResource);560561/** \brief Returns memory heap that the resource is created in.562563If the Allocation represents committed resource with implicit heap, returns NULL.564*/565ID3D12Heap* GetHeap() const;566567/// Changes custom pointer for an allocation to a new value.568void SetPrivateData(void* pPrivateData) { m_pPrivateData = pPrivateData; }569570/// Get custom pointer associated with the allocation.571void* GetPrivateData() const { return m_pPrivateData; }572573/** \brief Associates a name with the allocation object. This name is for use in debug diagnostics and tools.574575Internal copy of the string is made, so the memory pointed by the argument can be576changed of freed immediately after this call.577578`Name` can be null.579*/580void SetName(LPCWSTR Name);581582/** \brief Returns the name associated with the allocation object.583584Returned string points to an internal copy.585586If no name was associated with the allocation, returns null.587*/588LPCWSTR GetName() const { return m_Name; }589590protected:591void ReleaseThis() override;592593private:594friend class AllocatorPimpl;595friend class BlockVector;596friend class CommittedAllocationList;597friend class JsonWriter;598friend class BlockMetadata_Linear;599friend class DefragmentationContextPimpl;600friend struct CommittedAllocationListItemTraits;601template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);602template<typename T> friend class PoolAllocator;603604enum Type605{606TYPE_COMMITTED,607TYPE_PLACED,608TYPE_HEAP,609TYPE_COUNT610};611612AllocatorPimpl* m_Allocator;613UINT64 m_Size;614UINT64 m_Alignment;615ID3D12Resource* m_Resource;616void* m_pPrivateData;617wchar_t* m_Name;618619union620{621struct622{623CommittedAllocationList* list;624Allocation* prev;625Allocation* next;626} m_Committed;627628struct629{630AllocHandle allocHandle;631NormalBlock* block;632} m_Placed;633634struct635{636// Beginning must be compatible with m_Committed.637CommittedAllocationList* list;638Allocation* prev;639Allocation* next;640ID3D12Heap* heap;641} m_Heap;642};643644struct PackedData645{646public:647PackedData() :648m_Type(0), m_ResourceDimension(0), m_ResourceFlags(0), m_TextureLayout(0) { }649650Type GetType() const { return (Type)m_Type; }651D3D12_RESOURCE_DIMENSION GetResourceDimension() const { return (D3D12_RESOURCE_DIMENSION)m_ResourceDimension; }652D3D12_RESOURCE_FLAGS GetResourceFlags() const { return (D3D12_RESOURCE_FLAGS)m_ResourceFlags; }653D3D12_TEXTURE_LAYOUT GetTextureLayout() const { return (D3D12_TEXTURE_LAYOUT)m_TextureLayout; }654655void SetType(Type type);656void SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension);657void SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags);658void SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout);659660private:661UINT m_Type : 2; // enum Type662UINT m_ResourceDimension : 3; // enum D3D12_RESOURCE_DIMENSION663UINT m_ResourceFlags : 24; // flags D3D12_RESOURCE_FLAGS664UINT m_TextureLayout : 9; // enum D3D12_TEXTURE_LAYOUT665} m_PackedData;666667Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment);668// Nothing here, everything already done in Release.669virtual ~Allocation() = default;670671void InitCommitted(CommittedAllocationList* list);672void InitPlaced(AllocHandle allocHandle, NormalBlock* block);673void InitHeap(CommittedAllocationList* list, ID3D12Heap* heap);674void SwapBlockAllocation(Allocation* allocation);675// If the Allocation represents committed resource with implicit heap, returns UINT64_MAX.676AllocHandle GetAllocHandle() const;677NormalBlock* GetBlock();678template<typename D3D12_RESOURCE_DESC_T>679void SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc);680void FreeName();681682D3D12MA_CLASS_NO_COPY(Allocation)683};684685686/// Flags to be passed as DEFRAGMENTATION_DESC::Flags.687enum DEFRAGMENTATION_FLAGS688{689/** Use simple but fast algorithm for defragmentation.690May not achieve best results but will require least time to compute and least allocations to copy.691*/692DEFRAGMENTATION_FLAG_ALGORITHM_FAST = 0x1,693/** Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified.694Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved.695*/696DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED = 0x2,697/** Perform full defragmentation of memory.698Can result in notably more time to compute and allocations to copy, but will achieve best memory packing.699*/700DEFRAGMENTATION_FLAG_ALGORITHM_FULL = 0x4,701702/// A bit mask to extract only `ALGORITHM` bits from entire set of flags.703DEFRAGMENTATION_FLAG_ALGORITHM_MASK =704DEFRAGMENTATION_FLAG_ALGORITHM_FAST |705DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED |706DEFRAGMENTATION_FLAG_ALGORITHM_FULL707};708709/** \brief Parameters for defragmentation.710711To be used with functions Allocator::BeginDefragmentation() and Pool::BeginDefragmentation().712*/713struct DEFRAGMENTATION_DESC714{715/// Flags.716DEFRAGMENTATION_FLAGS Flags;717/** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places.7187190 means no limit.720*/721UINT64 MaxBytesPerPass;722/** \brief Maximum number of allocations that can be moved during single pass to a different place.7237240 means no limit.725*/726UINT32 MaxAllocationsPerPass;727};728729/// Operation performed on single defragmentation move.730enum DEFRAGMENTATION_MOVE_OPERATION731{732/** Resource has been recreated at `pDstTmpAllocation`, data has been copied, old resource has been destroyed.733`pSrcAllocation` will be changed to point to the new place. This is the default value set by DefragmentationContext::BeginPass().734*/735DEFRAGMENTATION_MOVE_OPERATION_COPY = 0,736/// Set this value if you cannot move the allocation. New place reserved at `pDstTmpAllocation` will be freed. `pSrcAllocation` will remain unchanged.737DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1,738/// Set this value if you decide to abandon the allocation and you destroyed the resource. New place reserved `pDstTmpAllocation` will be freed, along with `pSrcAllocation`.739DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2,740};741742/// Single move of an allocation to be done for defragmentation.743struct DEFRAGMENTATION_MOVE744{745/** \brief Operation to be performed on the allocation by DefragmentationContext::EndPass().746Default value is #DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.747*/748DEFRAGMENTATION_MOVE_OPERATION Operation;749/// %Allocation that should be moved.750Allocation* pSrcAllocation;751/** \brief Temporary allocation pointing to destination memory that will replace `pSrcAllocation`.752753Use it to retrieve new `ID3D12Heap` and offset to create new `ID3D12Resource` and then store it here via Allocation::SetResource().754755\warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass,756to be used for storing newly created resource. DefragmentationContext::EndPass() will destroy it and make `pSrcAllocation` point to this memory.757*/758Allocation* pDstTmpAllocation;759};760761/** \brief Parameters for incremental defragmentation steps.762763To be used with function DefragmentationContext::BeginPass().764*/765struct DEFRAGMENTATION_PASS_MOVE_INFO766{767/// Number of elements in the `pMoves` array.768UINT32 MoveCount;769/** \brief Array of moves to be performed by the user in the current defragmentation pass.770771Pointer to an array of `MoveCount` elements, owned by %D3D12MA, created in DefragmentationContext::BeginPass(), destroyed in DefragmentationContext::EndPass().772773For each element, you should:7747751. Create a new resource in the place pointed by `pMoves[i].pDstTmpAllocation->GetHeap()` + `pMoves[i].pDstTmpAllocation->GetOffset()`.7762. Store new resource in `pMoves[i].pDstTmpAllocation` by using Allocation::SetResource(). It will later replace old resource from `pMoves[i].pSrcAllocation`.7773. Copy data from the `pMoves[i].pSrcAllocation` e.g. using `D3D12GraphicsCommandList::CopyResource`.7784. Make sure these commands finished executing on the GPU.779780Only then you can finish defragmentation pass by calling DefragmentationContext::EndPass().781After this call, the allocation will point to the new place in memory.782783Alternatively, if you cannot move specific allocation,784you can set DEFRAGMENTATION_MOVE::Operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.785786Alternatively, if you decide you want to completely remove the allocation,787set DEFRAGMENTATION_MOVE::Operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY.788Then, after DefragmentationContext::EndPass() the allocation will be released.789*/790DEFRAGMENTATION_MOVE* pMoves;791};792793/// %Statistics returned for defragmentation process by function DefragmentationContext::GetStats().794struct DEFRAGMENTATION_STATS795{796/// Total number of bytes that have been copied while moving allocations to different places.797UINT64 BytesMoved;798/// Total number of bytes that have been released to the system by freeing empty heaps.799UINT64 BytesFreed;800/// Number of allocations that have been moved to different places.801UINT32 AllocationsMoved;802/// Number of empty `ID3D12Heap` objects that have been released to the system.803UINT32 HeapsFreed;804};805806/** \brief Represents defragmentation process in progress.807808You can create this object using Allocator::BeginDefragmentation (for default pools) or809Pool::BeginDefragmentation (for a custom pool).810*/811class D3D12MA_API DefragmentationContext : public IUnknownImpl812{813public:814/** \brief Starts single defragmentation pass.815816\param[out] pPassInfo Computed informations for current pass.817\returns818- `S_OK` if no more moves are possible. Then you can omit call to DefragmentationContext::EndPass() and simply end whole defragmentation.819- `S_FALSE` if there are pending moves returned in `pPassInfo`. You need to perform them, call DefragmentationContext::EndPass(),820and then preferably try another pass with DefragmentationContext::BeginPass().821*/822HRESULT BeginPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo);823/** \brief Ends single defragmentation pass.824825\param pPassInfo Computed informations for current pass filled by DefragmentationContext::BeginPass() and possibly modified by you.826\return Returns `S_OK` if no more moves are possible or `S_FALSE` if more defragmentations are possible.827828Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`.829After this call:830831- %Allocation at `pPassInfo[i].pSrcAllocation` that had `pPassInfo[i].Operation ==` #DEFRAGMENTATION_MOVE_OPERATION_COPY832(which is the default) will be pointing to the new destination place.833- %Allocation at `pPassInfo[i].pSrcAllocation` that had `pPassInfo[i].operation ==` #DEFRAGMENTATION_MOVE_OPERATION_DESTROY834will be released.835836If no more moves are possible you can end whole defragmentation.837*/838HRESULT EndPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo);839/** \brief Returns statistics of the defragmentation performed so far.840*/841void GetStats(DEFRAGMENTATION_STATS* pStats);842843protected:844void ReleaseThis() override;845846private:847friend class Pool;848friend class Allocator;849template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);850851DefragmentationContextPimpl* m_Pimpl;852853DefragmentationContext(AllocatorPimpl* allocator,854const DEFRAGMENTATION_DESC& desc,855BlockVector* poolVector);856~DefragmentationContext();857858D3D12MA_CLASS_NO_COPY(DefragmentationContext)859};860861/// \brief Bit flags to be used with POOL_DESC::Flags.862enum POOL_FLAGS863{864/// Zero865POOL_FLAG_NONE = 0,866867/** Enables alternative, linear allocation algorithm in this pool.868869Specify this flag to enable linear allocation algorithm, which always creates870new allocations after last one and doesn't reuse space from allocations freed in871between. It trades memory consumption for simplified algorithm and data872structure, which has better performance and uses less memory for metadata.873874By using this flag, you can achieve behavior of free-at-once, stack,875ring buffer, and double stack.876For details, see documentation chapter \ref linear_algorithm.877*/878POOL_FLAG_ALGORITHM_LINEAR = 0x1,879880/** Optimization, allocate MSAA textures as committed resources always.881882Specify this flag to create MSAA textures with implicit heaps, as if they were created883with flag D3D12MA::ALLOCATION_FLAG_COMMITTED. Usage of this flags enables pool to create its heaps884on smaller alignment not suitable for MSAA textures.885886You should always use this flag unless you really need to create some MSAA textures in this pool as placed.887*/888POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x2,889/** Every allocation made in this pool will be created as a committed resource - will have its own memory block.890891There is also an equivalent flag for the entire allocator: D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED.892*/893POOL_FLAG_ALWAYS_COMMITTED = 0x4,894895// Bit mask to extract only `ALGORITHM` bits from entire set of flags.896POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_LINEAR897};898899/// \brief Parameters of created D3D12MA::Pool object. To be used with D3D12MA::Allocator::CreatePool.900struct POOL_DESC901{902/** \brief Flags for the heap.903904It is recommended to use #D3D12MA_RECOMMENDED_HEAP_FLAGS.905*/906POOL_FLAGS Flags;907/** \brief The parameters of memory heap where allocations of this pool should be placed.908909In the simplest case, just fill it with zeros and set `Type` to one of: `D3D12_HEAP_TYPE_DEFAULT`,910`D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`. Additional parameters can be used e.g. to utilize UMA.911*/912D3D12_HEAP_PROPERTIES HeapProperties;913/** \brief Heap flags to be used when allocating heaps of this pool.914915It should contain one of these values, depending on type of resources you are going to create in this heap:916`D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,917`D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,918`D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.919Except if ResourceHeapTier = 2, then it may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.920921It is recommended to also add #D3D12MA_RECOMMENDED_POOL_FLAGS.922You can specify additional flags if needed.923*/924D3D12_HEAP_FLAGS HeapFlags;925/** \brief Size of a single heap (memory block) to be allocated as part of this pool, in bytes. Optional.926927Specify nonzero to set explicit, constant size of memory blocks used by this pool.928Leave 0 to use default and let the library manage block sizes automatically.929Then sizes of particular blocks may vary.930*/931UINT64 BlockSize;932/** \brief Minimum number of heaps (memory blocks) to be always allocated in this pool, even if they stay empty. Optional.933934Set to 0 to have no preallocated blocks and allow the pool be completely empty.935*/936UINT MinBlockCount;937/** \brief Maximum number of heaps (memory blocks) that can be allocated in this pool. Optional.938939Set to 0 to use default, which is `UINT64_MAX`, which means no limit.940941Set to same value as D3D12MA::POOL_DESC::MinBlockCount to have fixed amount of memory allocated942throughout whole lifetime of this pool.943*/944UINT MaxBlockCount;945/** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0.946947Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two.948*/949UINT64 MinAllocationAlignment;950/** \brief Additional parameter allowing pool to create resources with passed protected session.951952If not null then all the heaps and committed resources will be created with this parameter.953Valid only if ID3D12Device4 interface is present in current Windows SDK!954*/955ID3D12ProtectedResourceSession* pProtectedSession;956/** \brief Residency priority to be set for all allocations made in this pool. Optional.957958Set this parameter to one of the possible enum values e.g. `D3D12_RESIDENCY_PRIORITY_HIGH`959to apply specific residency priority to all allocations made in this pool:960`ID3D12Heap` memory blocks used to sub-allocate for placed resources, as well as961committed resources or heaps created when D3D12MA::ALLOCATION_FLAG_COMMITTED is used.962This can increase/decrease chance that the memory will be pushed out from VRAM963to system RAM when the system runs out of memory, which is invisible to the developer964using D3D12 API while it can degrade performance.965966Priority is set using function `ID3D12Device1::SetResidencyPriority`.967It is performed only when `ID3D12Device1` interface is defined and successfully obtained.968Otherwise, this parameter is ignored.969970This parameter is optional. If you set it to `D3D12_RESIDENCY_PRIORITY(0)`,971residency priority will not be set for allocations made in this pool.972973There is no equivalent parameter for allocations made in default pools.974If you want to set residency priority for such allocation, you need to do it manually:975allocate with D3D12MA::ALLOCATION_FLAG_COMMITTED and call976`ID3D12Device1::SetResidencyPriority`, passing `allocation->GetResource()`.977*/978D3D12_RESIDENCY_PRIORITY ResidencyPriority;979};980981/** \brief Custom memory pool982983Represents a separate set of heaps (memory blocks) that can be used to create984D3D12MA::Allocation-s and resources in it. Usually there is no need to create custom985pools - creating resources in default pool is sufficient.986987To create custom pool, fill D3D12MA::POOL_DESC and call D3D12MA::Allocator::CreatePool.988*/989class D3D12MA_API Pool : public IUnknownImpl990{991public:992/** \brief Returns copy of parameters of the pool.993994These are the same parameters as passed to D3D12MA::Allocator::CreatePool.995*/996POOL_DESC GetDesc() const;997998/** \brief Retrieves basic statistics of the custom pool that are fast to calculate.9991000\param[out] pStats %Statistics of the current pool.1001*/1002void GetStatistics(Statistics* pStats);10031004/** \brief Retrieves detailed statistics of the custom pool that are slower to calculate.10051006\param[out] pStats %Statistics of the current pool.1007*/1008void CalculateStatistics(DetailedStatistics* pStats);10091010/** \brief Associates a name with the pool. This name is for use in debug diagnostics and tools.10111012Internal copy of the string is made, so the memory pointed by the argument can be1013changed of freed immediately after this call.10141015`Name` can be NULL.1016*/1017void SetName(LPCWSTR Name);10181019/** \brief Returns the name associated with the pool object.10201021Returned string points to an internal copy.10221023If no name was associated with the allocation, returns NULL.1024*/1025LPCWSTR GetName() const;10261027/** \brief Begins defragmentation process of the current pool.10281029\param pDesc Structure filled with parameters of defragmentation.1030\param[out] ppContext Context object that will manage defragmentation.1031\returns1032- `S_OK` if defragmentation can begin.1033- `E_NOINTERFACE` if defragmentation is not supported.10341035For more information about defragmentation, see documentation chapter:1036[Defragmentation](@ref defragmentation).1037*/1038HRESULT BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext);10391040protected:1041void ReleaseThis() override;10421043private:1044friend class Allocator;1045friend class AllocatorPimpl;1046template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);10471048PoolPimpl* m_Pimpl;10491050Pool(Allocator* allocator, const POOL_DESC &desc);1051~Pool();10521053D3D12MA_CLASS_NO_COPY(Pool)1054};105510561057/// \brief Bit flags to be used with ALLOCATOR_DESC::Flags.1058enum ALLOCATOR_FLAGS1059{1060/// Zero1061ALLOCATOR_FLAG_NONE = 0,10621063/**1064Allocator and all objects created from it will not be synchronized internally,1065so you must guarantee they are used from only one thread at a time or1066synchronized by you.10671068Using this flag may increase performance because internal mutexes are not used.1069*/1070ALLOCATOR_FLAG_SINGLETHREADED = 0x1,10711072/** Every allocation will be created as a committed resource - will have its own memory block.10731074Affects both default pools and custom pools.1075To be used for debugging purposes only.1076There is also an equivalent flag for custom pools: D3D12MA::POOL_FLAG_ALWAYS_COMMITTED.1077*/1078ALLOCATOR_FLAG_ALWAYS_COMMITTED = 0x2,10791080/**1081Heaps created for the default pools will be created with flag `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED`,1082allowing for their memory to be not zeroed by the system if possible,1083which can speed up allocation.10841085Only affects default pools.1086To use the flag with @ref custom_pools, you need to add it manually:10871088\code1089poolDesc.heapFlags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;1090\endcode10911092Only avaiable if `ID3D12Device8` is present. Otherwise, the flag is ignored.1093*/1094ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED = 0x4,10951096/** Optimization, allocate MSAA textures as committed resources always.10971098Specify this flag to create MSAA textures with implicit heaps, as if they were created1099with flag D3D12MA::ALLOCATION_FLAG_COMMITTED. Usage of this flags enables all default pools1100to create its heaps on smaller alignment not suitable for MSAA textures.11011102You should always use this flag unless you really need to create some MSAA textures as placed.1103*/1104ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x8,1105/** Disable optimization that prefers creating small buffers as committed to avoid 64 KB alignment.11061107By default, the library prefers creating small buffers <= 32 KB as committed,1108because drivers tend to pack them better, while placed buffers require 64 KB alignment.1109This, however, may decrease performance, as creating committed resources involves allocation of implicit heaps,1110which may take longer than creating placed resources in existing heaps.1111Passing this flag will disable this committed preference globally for the allocator.1112It can also be disabled for a single allocation by using #ALLOCATION_FLAG_STRATEGY_MIN_TIME.1113*/1114ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED = 0x10,1115};11161117/// \brief Parameters of created Allocator object. To be used with CreateAllocator().1118struct ALLOCATOR_DESC1119{1120/** \brief Flags for the entire allocator.11211122It is recommended to use #D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS.1123*/1124ALLOCATOR_FLAGS Flags;11251126/** Direct3D device object that the allocator should be attached to.11271128Allocator is doing `AddRef`/`Release` on this object.1129*/1130ID3D12Device* pDevice;11311132/** \brief Preferred size of a single `ID3D12Heap` block to be allocated.11331134Set to 0 to use default, which is currently 64 MiB.1135*/1136UINT64 PreferredBlockSize;11371138/** \brief Custom CPU memory allocation callbacks. Optional.11391140Optional, can be null. When specified, will be used for all CPU-side memory allocations.1141*/1142const ALLOCATION_CALLBACKS* pAllocationCallbacks;11431144/** DXGI Adapter object that you use for D3D12 and this allocator.11451146Allocator is doing `AddRef`/`Release` on this object.1147*/1148IDXGIAdapter* pAdapter;1149};11501151/**1152\brief Represents main object of this library initialized for particular `ID3D12Device`.11531154Fill structure D3D12MA::ALLOCATOR_DESC and call function CreateAllocator() to create it.1155Call method `Release()` to destroy it.11561157It is recommended to create just one object of this type per `ID3D12Device` object,1158right after Direct3D 12 is initialized and keep it alive until before Direct3D device is destroyed.1159*/1160class D3D12MA_API Allocator : public IUnknownImpl1161{1162public:1163/// Returns cached options retrieved from D3D12 device.1164const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const;1165/** \brief Returns true if `D3D12_FEATURE_DATA_ARCHITECTURE1::UMA` was found to be true.11661167For more information about how to use it, see articles in Microsoft Docs articles:11681169- "UMA Optimizations: CPU Accessible Textures and Standard Swizzle"1170- "D3D12_FEATURE_DATA_ARCHITECTURE structure (d3d12.h)"1171- "ID3D12Device::GetCustomHeapProperties method (d3d12.h)"1172*/1173BOOL IsUMA() const;1174/** \brief Returns true if `D3D12_FEATURE_DATA_ARCHITECTURE1::CacheCoherentUMA` was found to be true.11751176For more information about how to use it, see articles in Microsoft Docs articles:11771178- "UMA Optimizations: CPU Accessible Textures and Standard Swizzle"1179- "D3D12_FEATURE_DATA_ARCHITECTURE structure (d3d12.h)"1180- "ID3D12Device::GetCustomHeapProperties method (d3d12.h)"1181*/1182BOOL IsCacheCoherentUMA() const;1183/** \brief Returns true if GPU Upload Heaps are supported on the current system.11841185When true, you can use `D3D12_HEAP_TYPE_GPU_UPLOAD`.11861187This flag is fetched from `D3D12_FEATURE_D3D12_OPTIONS16::GPUUploadHeapSupported`.1188*/1189BOOL IsGPUUploadHeapSupported() const;1190/** \brief Returns total amount of memory of specific segment group, in bytes.11911192\param memorySegmentGroup use `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` or `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`.11931194This information is taken from `DXGI_ADAPTER_DESC`.1195It is not recommended to use this number.1196You should preferably call GetBudget() and limit memory usage to D3D12MA::Budget::BudgetBytes instead.11971198- When IsUMA() `== FALSE` (discrete graphics card):1199- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)` returns the size of the video memory.1200- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)` returns the size of the system memory available for D3D12 resources.1201- When IsUMA() `== TRUE` (integrated graphics chip):1202- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)` returns the size of the shared memory available for all D3D12 resources.1203All memory is considered "local".1204- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)` is not applicable and returns 0.1205*/1206UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;12071208/** \brief Allocates memory and creates a D3D12 resource (buffer or texture). This is the main allocation function.12091210The function is similar to `ID3D12Device::CreateCommittedResource`, but it may1211really call `ID3D12Device::CreatePlacedResource` to assign part of a larger,1212existing memory heap to the new resource, which is the main purpose of this1213whole library.12141215If `ppvResource` is null, you receive only `ppAllocation` object from this function.1216It holds pointer to `ID3D12Resource` that can be queried using function D3D12MA::Allocation::GetResource().1217Reference count of the resource object is 1.1218It is automatically destroyed when you destroy the allocation object.12191220If `ppvResource` is not null, you receive pointer to the resource next to allocation object.1221Reference count of the resource object is then increased by calling `QueryInterface`, so you need to manually `Release` it1222along with the allocation.12231224\param pAllocDesc Parameters of the allocation.1225\param pResourceDesc Description of created resource.1226\param InitialResourceState Initial resource state.1227\param pOptimizedClearValue Optional. Either null or optimized clear value.1228\param[out] ppAllocation Filled with pointer to new allocation object created.1229\param riidResource IID of a resource to be returned via `ppvResource`.1230\param[out] ppvResource Optional. If not null, filled with pointer to new resouce created.12311232\note This function creates a new resource. Sub-allocation of parts of one large buffer,1233although recommended as a good practice, is out of scope of this library and could be implemented1234by the user as a higher-level logic on top of it, e.g. using the \ref virtual_allocator feature.1235*/1236HRESULT CreateResource(1237const ALLOCATION_DESC* pAllocDesc,1238const D3D12_RESOURCE_DESC* pResourceDesc,1239D3D12_RESOURCE_STATES InitialResourceState,1240const D3D12_CLEAR_VALUE *pOptimizedClearValue,1241Allocation** ppAllocation,1242REFIID riidResource,1243void** ppvResource);12441245#ifdef __ID3D12Device8_INTERFACE_DEFINED__1246/** \brief Similar to Allocator::CreateResource, but supports new structure `D3D12_RESOURCE_DESC1`.12471248It internally uses `ID3D12Device8::CreateCommittedResource2` or `ID3D12Device8::CreatePlacedResource1`.12491250To work correctly, `ID3D12Device8` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.1251*/1252HRESULT CreateResource2(1253const ALLOCATION_DESC* pAllocDesc,1254const D3D12_RESOURCE_DESC1* pResourceDesc,1255D3D12_RESOURCE_STATES InitialResourceState,1256const D3D12_CLEAR_VALUE *pOptimizedClearValue,1257Allocation** ppAllocation,1258REFIID riidResource,1259void** ppvResource);1260#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__12611262#ifdef __ID3D12Device10_INTERFACE_DEFINED__1263/** \brief Similar to Allocator::CreateResource2, but there are initial layout instead of state and1264castable formats list12651266It internally uses `ID3D12Device10::CreateCommittedResource3` or `ID3D12Device10::CreatePlacedResource2`.12671268To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.1269*/1270HRESULT CreateResource3(const ALLOCATION_DESC* pAllocDesc,1271const D3D12_RESOURCE_DESC1* pResourceDesc,1272D3D12_BARRIER_LAYOUT InitialLayout,1273const D3D12_CLEAR_VALUE* pOptimizedClearValue,1274UINT32 NumCastableFormats,1275DXGI_FORMAT* pCastableFormats,1276Allocation** ppAllocation,1277REFIID riidResource,1278void** ppvResource);1279#endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__12801281/** \brief Allocates memory without creating any resource placed in it.12821283This function is similar to `ID3D12Device::CreateHeap`, but it may really assign1284part of a larger, existing heap to the allocation.12851286`pAllocDesc->heapFlags` should contain one of these values, depending on type of resources you are going to create in this memory:1287`D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,1288`D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,1289`D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.1290Except if you validate that ResourceHeapTier = 2 - then `heapFlags`1291may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.1292Additional flags in `heapFlags` are allowed as well.12931294`pAllocInfo->SizeInBytes` must be multiply of 64KB.1295`pAllocInfo->Alignment` must be one of the legal values as described in documentation of `D3D12_HEAP_DESC`.12961297If you use D3D12MA::ALLOCATION_FLAG_COMMITTED you will get a separate memory block -1298a heap that always has offset 0.1299*/1300HRESULT AllocateMemory(1301const ALLOCATION_DESC* pAllocDesc,1302const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,1303Allocation** ppAllocation);13041305/** \brief Creates a new resource in place of an existing allocation. This is useful for memory aliasing.13061307\param pAllocation Existing allocation indicating the memory where the new resource should be created.1308It can be created using D3D12MA::Allocator::CreateResource and already have a resource bound to it,1309or can be a raw memory allocated with D3D12MA::Allocator::AllocateMemory.1310It must not be created as committed so that `ID3D12Heap` is available and not implicit.1311\param AllocationLocalOffset Additional offset in bytes to be applied when allocating the resource.1312Local from the start of `pAllocation`, not the beginning of the whole `ID3D12Heap`!1313If the new resource should start from the beginning of the `pAllocation` it should be 0.1314\param pResourceDesc Description of the new resource to be created.1315\param InitialResourceState1316\param pOptimizedClearValue1317\param riidResource1318\param[out] ppvResource Returns pointer to the new resource.1319The resource is not bound with `pAllocation`.1320This pointer must not be null - you must get the resource pointer and `Release` it when no longer needed.13211322Memory requirements of the new resource are checked for validation.1323If its size exceeds the end of `pAllocation` or required alignment is not fulfilled1324considering `pAllocation->GetOffset() + AllocationLocalOffset`, the function1325returns `E_INVALIDARG`.1326*/1327HRESULT CreateAliasingResource(1328Allocation* pAllocation,1329UINT64 AllocationLocalOffset,1330const D3D12_RESOURCE_DESC* pResourceDesc,1331D3D12_RESOURCE_STATES InitialResourceState,1332const D3D12_CLEAR_VALUE *pOptimizedClearValue,1333REFIID riidResource,1334void** ppvResource);13351336#ifdef __ID3D12Device8_INTERFACE_DEFINED__1337/** \brief Similar to Allocator::CreateAliasingResource, but supports new structure `D3D12_RESOURCE_DESC1`.13381339It internally uses `ID3D12Device8::CreatePlacedResource1`.13401341To work correctly, `ID3D12Device8` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.1342*/1343HRESULT CreateAliasingResource1(Allocation* pAllocation,1344UINT64 AllocationLocalOffset,1345const D3D12_RESOURCE_DESC1* pResourceDesc,1346D3D12_RESOURCE_STATES InitialResourceState,1347const D3D12_CLEAR_VALUE* pOptimizedClearValue,1348REFIID riidResource,1349void** ppvResource);1350#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__13511352#ifdef __ID3D12Device10_INTERFACE_DEFINED__1353/** \brief Similar to Allocator::CreateAliasingResource1, but there are initial layout instead of state and1354castable formats list13551356It internally uses `ID3D12Device10::CreatePlacedResource2`.13571358To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.1359*/1360HRESULT CreateAliasingResource2(Allocation* pAllocation,1361UINT64 AllocationLocalOffset,1362const D3D12_RESOURCE_DESC1* pResourceDesc,1363D3D12_BARRIER_LAYOUT InitialLayout,1364const D3D12_CLEAR_VALUE* pOptimizedClearValue,1365UINT32 NumCastableFormats,1366DXGI_FORMAT* pCastableFormats,1367REFIID riidResource,1368void** ppvResource);1369#endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__13701371/** \brief Creates custom pool.1372*/1373HRESULT CreatePool(1374const POOL_DESC* pPoolDesc,1375Pool** ppPool);13761377/** \brief Sets the index of the current frame.13781379This function is used to set the frame index in the allocator when a new game frame begins.1380*/1381void SetCurrentFrameIndex(UINT frameIndex);13821383/** \brief Retrieves information about current memory usage and budget.13841385\param[out] pLocalBudget Optional, can be null.1386\param[out] pNonLocalBudget Optional, can be null.13871388- When IsUMA() `== FALSE` (discrete graphics card):1389- `pLocalBudget` returns the budget of the video memory.1390- `pNonLocalBudget` returns the budget of the system memory available for D3D12 resources.1391- When IsUMA() `== TRUE` (integrated graphics chip):1392- `pLocalBudget` returns the budget of the shared memory available for all D3D12 resources.1393All memory is considered "local".1394- `pNonLocalBudget` is not applicable and returns zeros.13951396This function is called "get" not "calculate" because it is very fast, suitable to be called1397every frame or every allocation. For more detailed statistics use CalculateStatistics().13981399Note that when using allocator from multiple threads, returned information may immediately1400become outdated.1401*/1402void GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget);14031404/** \brief Retrieves statistics from current state of the allocator.14051406This function is called "calculate" not "get" because it has to traverse all1407internal data structures, so it may be quite slow. Use it for debugging purposes.1408For faster but more brief statistics suitable to be called every frame or every allocation,1409use GetBudget().14101411Note that when using allocator from multiple threads, returned information may immediately1412become outdated.1413*/1414void CalculateStatistics(TotalStatistics* pStats);14151416/** \brief Builds and returns statistics as a string in JSON format.1417*1418@param[out] ppStatsString Must be freed using Allocator::FreeStatsString.1419@param DetailedMap `TRUE` to include full list of allocations (can make the string quite long), `FALSE` to only return statistics.1420*/1421void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const;14221423/// Frees memory of a string returned from Allocator::BuildStatsString.1424void FreeStatsString(WCHAR* pStatsString) const;14251426/** \brief Begins defragmentation process of the default pools.14271428\param pDesc Structure filled with parameters of defragmentation.1429\param[out] ppContext Context object that will manage defragmentation.14301431For more information about defragmentation, see documentation chapter:1432[Defragmentation](@ref defragmentation).1433*/1434void BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext);14351436protected:1437void ReleaseThis() override;14381439private:1440friend D3D12MA_API HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);1441template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);1442friend class DefragmentationContext;1443friend class Pool;14441445Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);1446~Allocator();14471448AllocatorPimpl* m_Pimpl;14491450D3D12MA_CLASS_NO_COPY(Allocator)1451};145214531454/// \brief Bit flags to be used with VIRTUAL_BLOCK_DESC::Flags.1455enum VIRTUAL_BLOCK_FLAGS1456{1457/// Zero1458VIRTUAL_BLOCK_FLAG_NONE = 0,14591460/** \brief Enables alternative, linear allocation algorithm in this virtual block.14611462Specify this flag to enable linear allocation algorithm, which always creates1463new allocations after last one and doesn't reuse space from allocations freed in1464between. It trades memory consumption for simplified algorithm and data1465structure, which has better performance and uses less memory for metadata.14661467By using this flag, you can achieve behavior of free-at-once, stack,1468ring buffer, and double stack.1469For details, see documentation chapter \ref linear_algorithm.1470*/1471VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR = POOL_FLAG_ALGORITHM_LINEAR,14721473// Bit mask to extract only `ALGORITHM` bits from entire set of flags.1474VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_MASK1475};14761477/// Parameters of created D3D12MA::VirtualBlock object to be passed to CreateVirtualBlock().1478struct VIRTUAL_BLOCK_DESC1479{1480/// Flags.1481VIRTUAL_BLOCK_FLAGS Flags;1482/** \brief Total size of the block.14831484Sizes can be expressed in bytes or any units you want as long as you are consistent in using them.1485For example, if you allocate from some array of structures, 1 can mean single instance of entire structure.1486*/1487UINT64 Size;1488/** \brief Custom CPU memory allocation callbacks. Optional.14891490Optional, can be null. When specified, will be used for all CPU-side memory allocations.1491*/1492const ALLOCATION_CALLBACKS* pAllocationCallbacks;1493};14941495/// \brief Bit flags to be used with VIRTUAL_ALLOCATION_DESC::Flags.1496enum VIRTUAL_ALLOCATION_FLAGS1497{1498/// Zero1499VIRTUAL_ALLOCATION_FLAG_NONE = 0,15001501/** \brief Allocation will be created from upper stack in a double stack pool.15021503This flag is only allowed for virtual blocks created with #VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR flag.1504*/1505VIRTUAL_ALLOCATION_FLAG_UPPER_ADDRESS = ALLOCATION_FLAG_UPPER_ADDRESS,15061507/// %Allocation strategy that tries to minimize memory usage.1508VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_MEMORY = ALLOCATION_FLAG_STRATEGY_MIN_MEMORY,1509/// %Allocation strategy that tries to minimize allocation time.1510VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_TIME = ALLOCATION_FLAG_STRATEGY_MIN_TIME,1511/** %Allocation strategy that chooses always the lowest offset in available space.1512This is not the most efficient strategy but achieves highly packed data.1513*/1514VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_OFFSET = ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,1515/** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags.15161517These strategy flags are binary compatible with equivalent flags in #ALLOCATION_FLAGS.1518*/1519VIRTUAL_ALLOCATION_FLAG_STRATEGY_MASK = ALLOCATION_FLAG_STRATEGY_MASK,1520};15211522/// Parameters of created virtual allocation to be passed to VirtualBlock::Allocate().1523struct VIRTUAL_ALLOCATION_DESC1524{1525/// Flags for the virtual allocation.1526VIRTUAL_ALLOCATION_FLAGS Flags;1527/** \brief Size of the allocation.15281529Cannot be zero.1530*/1531UINT64 Size;1532/** \brief Required alignment of the allocation.15331534Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset.1535*/1536UINT64 Alignment;1537/** \brief Custom pointer to be associated with the allocation.15381539It can be fetched or changed later.1540*/1541void* pPrivateData;1542};15431544/// Parameters of an existing virtual allocation, returned by VirtualBlock::GetAllocationInfo().1545struct VIRTUAL_ALLOCATION_INFO1546{1547/// \brief Offset of the allocation.1548UINT64 Offset;1549/** \brief Size of the allocation.15501551Same value as passed in VIRTUAL_ALLOCATION_DESC::Size.1552*/1553UINT64 Size;1554/** \brief Custom pointer associated with the allocation.15551556Same value as passed in VIRTUAL_ALLOCATION_DESC::pPrivateData or VirtualBlock::SetAllocationPrivateData().1557*/1558void* pPrivateData;1559};15601561/** \brief Represents pure allocation algorithm and a data structure with allocations in some memory block, without actually allocating any GPU memory.15621563This class allows to use the core algorithm of the library custom allocations e.g. CPU memory or1564sub-allocation regions inside a single GPU buffer.15651566To create this object, fill in D3D12MA::VIRTUAL_BLOCK_DESC and call CreateVirtualBlock().1567To destroy it, call its method `VirtualBlock::Release()`.1568You need to free all the allocations within this block or call Clear() before destroying it.15691570This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally.1571*/1572class D3D12MA_API VirtualBlock : public IUnknownImpl1573{1574public:1575/** \brief Returns true if the block is empty - contains 0 allocations.1576*/1577BOOL IsEmpty() const;1578/** \brief Returns information about an allocation - its offset, size and custom pointer.1579*/1580void GetAllocationInfo(VirtualAllocation allocation, VIRTUAL_ALLOCATION_INFO* pInfo) const;15811582/** \brief Creates new allocation.1583\param pDesc1584\param[out] pAllocation Unique indentifier of the new allocation within single block.1585\param[out] pOffset Returned offset of the new allocation. Optional, can be null.1586\return `S_OK` if allocation succeeded, `E_OUTOFMEMORY` if it failed.15871588If the allocation failed, `pAllocation->AllocHandle` is set to 0 and `pOffset`, if not null, is set to `UINT64_MAX`.1589*/1590HRESULT Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, VirtualAllocation* pAllocation, UINT64* pOffset);1591/** \brief Frees the allocation.15921593Calling this function with `allocation.AllocHandle == 0` is correct and does nothing.1594*/1595void FreeAllocation(VirtualAllocation allocation);1596/** \brief Frees all the allocations.1597*/1598void Clear();1599/** \brief Changes custom pointer for an allocation to a new value.1600*/1601void SetAllocationPrivateData(VirtualAllocation allocation, void* pPrivateData);1602/** \brief Retrieves basic statistics of the virtual block that are fast to calculate.16031604\param[out] pStats %Statistics of the virtual block.1605*/1606void GetStatistics(Statistics* pStats) const;1607/** \brief Retrieves detailed statistics of the virtual block that are slower to calculate.16081609\param[out] pStats %Statistics of the virtual block.1610*/1611void CalculateStatistics(DetailedStatistics* pStats) const;16121613/** \brief Builds and returns statistics as a string in JSON format, including the list of allocations with their parameters.1614@param[out] ppStatsString Must be freed using VirtualBlock::FreeStatsString.1615*/1616void BuildStatsString(WCHAR** ppStatsString) const;16171618/** \brief Frees memory of a string returned from VirtualBlock::BuildStatsString.1619*/1620void FreeStatsString(WCHAR* pStatsString) const;16211622protected:1623void ReleaseThis() override;16241625private:1626friend D3D12MA_API HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC*, VirtualBlock**);1627template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);16281629VirtualBlockPimpl* m_Pimpl;16301631VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);1632~VirtualBlock();16331634D3D12MA_CLASS_NO_COPY(VirtualBlock)1635};163616371638/** \brief Creates new main D3D12MA::Allocator object and returns it through `ppAllocator`.16391640You normally only need to call it once and keep a single Allocator object for your `ID3D12Device`.1641*/1642D3D12MA_API HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator);16431644/** \brief Creates new D3D12MA::VirtualBlock object and returns it through `ppVirtualBlock`.16451646Note you don't need to create D3D12MA::Allocator to use virtual blocks.1647*/1648D3D12MA_API HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock);16491650#ifndef D3D12MA_NO_HELPERS16511652/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::ALLOCATION_DESC structure.1653*/1654struct CALLOCATION_DESC : public ALLOCATION_DESC1655{1656/// Default constructor. Leaves the structure uninitialized.1657CALLOCATION_DESC() = default;1658/// Constructor initializing from the base D3D12MA::ALLOCATION_DESC structure.1659explicit CALLOCATION_DESC(const ALLOCATION_DESC& o) noexcept1660: ALLOCATION_DESC(o)1661{1662}1663/// Constructor initializing description of an allocation to be created in a specific custom pool.1664explicit CALLOCATION_DESC(Pool* customPool,1665ALLOCATION_FLAGS flags = ALLOCATION_FLAG_NONE,1666void* privateData = NULL) noexcept1667{1668Flags = flags;1669HeapType = (D3D12_HEAP_TYPE)0;1670ExtraHeapFlags = D3D12_HEAP_FLAG_NONE;1671CustomPool = customPool;1672pPrivateData = privateData;1673}1674/// Constructor initializing description of an allocation to be created in a default pool of a specific `D3D12_HEAP_TYPE`.1675explicit CALLOCATION_DESC(D3D12_HEAP_TYPE heapType,1676ALLOCATION_FLAGS flags = ALLOCATION_FLAG_NONE,1677void* privateData = NULL,1678D3D12_HEAP_FLAGS extraHeapFlags = D3D12MA_RECOMMENDED_HEAP_FLAGS) noexcept1679{1680Flags = flags;1681HeapType = heapType;1682ExtraHeapFlags = extraHeapFlags;1683CustomPool = NULL;1684pPrivateData = privateData;1685}1686};16871688/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::POOL_DESC structure.1689*/1690struct CPOOL_DESC : public POOL_DESC1691{1692/// Default constructor. Leaves the structure uninitialized.1693CPOOL_DESC() = default;1694/// Constructor initializing from the base D3D12MA::POOL_DESC structure.1695explicit CPOOL_DESC(const POOL_DESC& o) noexcept1696: POOL_DESC(o)1697{1698}1699/// Constructor initializing description of a custom pool created in one of the standard `D3D12_HEAP_TYPE`.1700explicit CPOOL_DESC(D3D12_HEAP_TYPE heapType,1701D3D12_HEAP_FLAGS heapFlags,1702POOL_FLAGS flags = D3D12MA_RECOMMENDED_POOL_FLAGS,1703UINT64 blockSize = 0,1704UINT minBlockCount = 0,1705UINT maxBlockCount = UINT_MAX,1706D3D12_RESIDENCY_PRIORITY residencyPriority = D3D12_RESIDENCY_PRIORITY_NORMAL) noexcept1707{1708Flags = flags;1709HeapProperties = {};1710HeapProperties.Type = heapType;1711HeapFlags = heapFlags;1712BlockSize = blockSize;1713MinBlockCount = minBlockCount;1714MaxBlockCount = maxBlockCount;1715MinAllocationAlignment = 0;1716pProtectedSession = NULL;1717ResidencyPriority = residencyPriority;1718}1719/// Constructor initializing description of a custom pool created with custom `D3D12_HEAP_PROPERTIES`.1720explicit CPOOL_DESC(const D3D12_HEAP_PROPERTIES heapProperties,1721D3D12_HEAP_FLAGS heapFlags,1722POOL_FLAGS flags = D3D12MA_RECOMMENDED_POOL_FLAGS,1723UINT64 blockSize = 0,1724UINT minBlockCount = 0,1725UINT maxBlockCount = UINT_MAX,1726D3D12_RESIDENCY_PRIORITY residencyPriority = D3D12_RESIDENCY_PRIORITY_NORMAL) noexcept1727{1728Flags = flags;1729HeapProperties = heapProperties;1730HeapFlags = heapFlags;1731BlockSize = blockSize;1732MinBlockCount = minBlockCount;1733MaxBlockCount = maxBlockCount;1734MinAllocationAlignment = 0;1735pProtectedSession = NULL;1736ResidencyPriority = residencyPriority;1737}1738};17391740/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::VIRTUAL_BLOCK_DESC structure.1741*/1742struct CVIRTUAL_BLOCK_DESC : public VIRTUAL_BLOCK_DESC1743{1744/// Default constructor. Leaves the structure uninitialized.1745CVIRTUAL_BLOCK_DESC() = default;1746/// Constructor initializing from the base D3D12MA::VIRTUAL_BLOCK_DESC structure.1747explicit CVIRTUAL_BLOCK_DESC(const VIRTUAL_BLOCK_DESC& o) noexcept1748: VIRTUAL_BLOCK_DESC(o)1749{1750}1751/// Constructor initializing description of a virtual block with given parameters.1752explicit CVIRTUAL_BLOCK_DESC(UINT64 size,1753VIRTUAL_BLOCK_FLAGS flags = VIRTUAL_BLOCK_FLAG_NONE,1754const ALLOCATION_CALLBACKS* allocationCallbacks = NULL) noexcept1755{1756Flags = flags;1757Size = size;1758pAllocationCallbacks = allocationCallbacks;1759}1760};17611762/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::VIRTUAL_ALLOCATION_DESC structure.1763*/1764struct CVIRTUAL_ALLOCATION_DESC : public VIRTUAL_ALLOCATION_DESC1765{1766/// Default constructor. Leaves the structure uninitialized.1767CVIRTUAL_ALLOCATION_DESC() = default;1768/// Constructor initializing from the base D3D12MA::VIRTUAL_ALLOCATION_DESC structure.1769explicit CVIRTUAL_ALLOCATION_DESC(const VIRTUAL_ALLOCATION_DESC& o) noexcept1770: VIRTUAL_ALLOCATION_DESC(o)1771{1772}1773/// Constructor initializing description of a virtual allocation with given parameters.1774explicit CVIRTUAL_ALLOCATION_DESC(UINT64 size, UINT64 alignment,1775VIRTUAL_ALLOCATION_FLAGS flags = VIRTUAL_ALLOCATION_FLAG_NONE,1776void* privateData = NULL) noexcept1777{1778Flags = flags;1779Size = size;1780Alignment = alignment;1781pPrivateData = privateData;1782}1783};17841785#endif // #ifndef D3D12MA_NO_HELPERS17861787} // namespace D3D12MA17881789/// \cond INTERNAL1790DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATION_FLAGS);1791DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::DEFRAGMENTATION_FLAGS);1792DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATOR_FLAGS);1793DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::POOL_FLAGS);1794DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_BLOCK_FLAGS);1795DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_ALLOCATION_FLAGS);1796/// \endcond17971798/**1799\page quick_start Quick start18001801\section quick_start_project_setup Project setup and initialization18021803This is a small, standalone C++ library. It consists of 2 files:1804"D3D12MemAlloc.h" header file with public interface and "D3D12MemAlloc.cpp" with1805internal implementation. The only external dependencies are WinAPI, Direct3D 12,1806and parts of C/C++ standard library (but STL containers, exceptions, or RTTI are1807not used).18081809The library is developed and tested using Microsoft Visual Studio 2022, but it1810should work with other compilers as well. It is designed for 64-bit code.18111812To use the library in your project:18131814(1.) Copy files `D3D12MemAlloc.cpp`, `%D3D12MemAlloc.h` to your project.18151816(2.) Make `D3D12MemAlloc.cpp` compiling as part of the project, as C++ code.18171818(3.) Include library header in each CPP file that needs to use the library.18191820\code1821#include "D3D12MemAlloc.h"1822\endcode18231824(4.) Right after you created `ID3D12Device`, fill D3D12MA::ALLOCATOR_DESC1825structure and call function D3D12MA::CreateAllocator to create the main1826D3D12MA::Allocator object.18271828Please note that all symbols of the library are declared inside #D3D12MA namespace.18291830\code1831IDXGIAdapter* adapter = ...1832ID3D12Device* device = ...18331834D3D12MA::ALLOCATOR_DESC allocatorDesc = {};1835allocatorDesc.pDevice = device;1836allocatorDesc.pAdapter = adapter;1837allocatorDesc.Flags = D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS;18381839D3D12MA::Allocator* allocator;1840HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);1841// Check hr...1842\endcode18431844(5.) Right before destroying the D3D12 device, destroy the allocator object.18451846\code1847allocator->Release();1848\endcode18491850Objects of this library must be destroyed by calling `Release` method.1851They are somewhat compatible with COM: they implement `IUnknown` interface with its virtual methods: `AddRef`, `Release`, `QueryInterface`,1852and they are reference-counted internally.1853You can use smart pointers designed for COM with objects of this library - e.g. `CComPtr` or `Microsoft::WRL::ComPtr`.1854The reference counter is thread-safe.1855`QueryInterface` method supports only `IUnknown`, as classes of this library don't define their own GUIDs.185618571858\section quick_start_creating_resources Creating resources18591860To use the library for creating resources (textures and buffers), call method1861D3D12MA::Allocator::CreateResource in the place where you would previously call1862`ID3D12Device::CreateCommittedResource`.18631864The function has similar syntax, but it expects structure D3D12MA::ALLOCATION_DESC1865to be passed along with `D3D12_RESOURCE_DESC` and other parameters for created1866resource. This structure describes parameters of the desired memory allocation,1867including choice of `D3D12_HEAP_TYPE`.18681869The function returns a new object of type D3D12MA::Allocation.1870It represents allocated memory and can be queried for size, offset, `ID3D12Heap`.1871It also holds a reference to the `ID3D12Resource`, which can be accessed by calling D3D12MA::Allocation::GetResource().18721873\code1874D3D12_RESOURCE_DESC resourceDesc = {};1875resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;1876resourceDesc.Alignment = 0;1877resourceDesc.Width = 1024;1878resourceDesc.Height = 1024;1879resourceDesc.DepthOrArraySize = 1;1880resourceDesc.MipLevels = 1;1881resourceDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;1882resourceDesc.SampleDesc.Count = 1;1883resourceDesc.SampleDesc.Quality = 0;1884resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;1885resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;18861887D3D12MA::ALLOCATION_DESC allocationDesc = {};1888allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;18891890D3D12MA::Allocation* allocation;1891HRESULT hr = allocator->CreateResource(1892&allocationDesc,1893&resourceDesc,1894D3D12_RESOURCE_STATE_COPY_DEST,1895NULL,1896&allocation,1897IID_NULL, NULL);1898// Check hr...18991900ID3D12Resource* res = allocation->GetResource();1901// Use res...1902\endcode19031904You need to release the allocation object when no longer needed.1905This will also release the D3D12 resource.19061907\code1908allocation->Release();1909\endcode19101911The advantage of using the allocator instead of creating committed resource, and1912the main purpose of this library, is that it can decide to allocate bigger memory1913heap internally using `ID3D12Device::CreateHeap` and place multiple resources in1914it, at different offsets, using `ID3D12Device::CreatePlacedResource`. The library1915manages its own collection of allocated memory blocks (heaps) and remembers which1916parts of them are occupied and which parts are free to be used for new resources.19171918It is important to remember that resources created as placed don't have their memory1919initialized to zeros, but may contain garbage data, so they need to be fully initialized1920before usage, e.g. using Clear (`ClearRenderTargetView`), Discard (`DiscardResource`),1921or Copy (`CopyResource`).19221923The library also automatically handles resource heap tier.1924When `D3D12_FEATURE_DATA_D3D12_OPTIONS::ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1`,1925resources of 3 types: buffers, textures that are render targets or depth-stencil,1926and other textures must be kept in separate heaps. When `D3D12_RESOURCE_HEAP_TIER_2`,1927they can be kept together. By using this library, you don't need to handle this1928manually.192919301931\section quick_start_resource_reference_counting Resource reference counting19321933`ID3D12Resource` and other interfaces of Direct3D 12 use COM, so they are reference-counted.1934Objects of this library are reference-counted as well.1935An object of type D3D12MA::Allocation remembers the resource (buffer or texture)1936that was created together with this memory allocation1937and holds a reference to the `ID3D12Resource` object.1938(Note this is a difference to Vulkan Memory Allocator, where a `VmaAllocation` object has no connection1939with the buffer or image that was created with it.)1940Thus, it is important to manage the resource reference counter properly.19411942<b>The simplest use case</b> is shown in the code snippet above.1943When only D3D12MA::Allocation object is obtained from a function call like D3D12MA::Allocator::CreateResource,1944it remembers the `ID3D12Resource` that was created with it and holds a reference to it.1945The resource can be obtained by calling `allocation->GetResource()`, which doesn't increment the resource1946reference counter.1947Calling `allocation->Release()` will decrease the resource reference counter, which is 1 in this case,1948so the resource will be released.19491950<b>Second option</b> is to retrieve a pointer to the resource along with D3D12MA::Allocation.1951Last parameters of the resource creation function can be used for this purpose.19521953\code1954D3D12MA::Allocation* allocation;1955ID3D12Resource* resource;1956HRESULT hr = allocator->CreateResource(1957&allocationDesc,1958&resourceDesc,1959D3D12_RESOURCE_STATE_COPY_DEST,1960NULL,1961&allocation,1962IID_PPV_ARGS(&resource));19631964// Use resource...1965\endcode19661967In this case, returned pointer `resource` is equal to `allocation->GetResource()`,1968but the creation function additionally increases resource reference counter for the purpose of returning it from this call1969(it actually calls `QueryInterface` internally), so the resource will have the counter = 2.1970The resource then need to be released along with the allocation, in this particular order,1971to make sure the resource is destroyed before its memory heap can potentially be freed.19721973\code1974resource->Release();1975allocation->Release();1976\endcode19771978<b>More advanced use cases</b> are possible when we consider that an D3D12MA::Allocation object can just hold1979a reference to any resource.1980It can be changed by calling D3D12MA::Allocation::SetResource. This function1981releases the old resource and calls `AddRef` on the new one.19821983Special care must be taken when performing <b>defragmentation</b>.1984The new resource created at the destination place should be set as `pass.pMoves[i].pDstTmpAllocation->SetResource(newRes)`,1985but it is moved to the source allocation at end of the defragmentation pass,1986while the old resource accessible through `pass.pMoves[i].pSrcAllocation->GetResource()` is then released.1987For more information, see documentation chapter \ref defragmentation.198819891990\section quick_start_mapping_memory Mapping memory19911992The process of getting regular CPU-side pointer to the memory of a resource in1993Direct3D is called "mapping". There are rules and restrictions to this process,1994as described in D3D12 documentation of `ID3D12Resource::Map` method.19951996Mapping happens on the level of particular resources, not entire memory heaps,1997and so it is out of scope of this library. Just as the documentation of the `Map` function says:19981999- Returned pointer refers to data of particular subresource, not entire memory heap.2000- You can map same resource multiple times. It is ref-counted internally.2001- Mapping is thread-safe.2002- Unmapping is not required before resource destruction.2003- Unmapping may not be required before using written data - some heap types on2004some platforms support resources persistently mapped.20052006When using this library, you can map and use your resources normally without2007considering whether they are created as committed resources or placed resources in one large heap.20082009Example for buffer created and filled in `UPLOAD` heap type:20102011\code2012const UINT64 bufSize = 65536;2013const float* bufData = ...;20142015D3D12_RESOURCE_DESC resourceDesc = {};2016resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;2017resourceDesc.Alignment = 0;2018resourceDesc.Width = bufSize;2019resourceDesc.Height = 1;2020resourceDesc.DepthOrArraySize = 1;2021resourceDesc.MipLevels = 1;2022resourceDesc.Format = DXGI_FORMAT_UNKNOWN;2023resourceDesc.SampleDesc.Count = 1;2024resourceDesc.SampleDesc.Quality = 0;2025resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;2026resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;20272028D3D12MA::ALLOCATION_DESC allocationDesc = {};2029allocationDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;20302031D3D12Resource* resource;2032D3D12MA::Allocation* allocation;2033HRESULT hr = allocator->CreateResource(2034&allocationDesc,2035&resourceDesc,2036D3D12_RESOURCE_STATE_GENERIC_READ,2037NULL,2038&allocation,2039IID_PPV_ARGS(&resource));20402041D3D12_RANGE emptyRange = {0, 0};2042void* mappedPtr;2043hr = resource->Map(0, &emptyRange, &mappedPtr);20442045memcpy(mappedPtr, bufData, bufSize);20462047resource->Unmap(0, NULL);2048\endcode204920502051\section quick_start_helper_structures Helper structures20522053DirectX 12 Agility SDK offers a library of helpers in files "build\native\include\d3dx12\*.h".2054They include structures that help with complete and concise initialization of the core D3D12 `*_DESC` structures2055by using some basic C++ features (constructors, static methods, default parameters).2056They inherit from these structures, so they support implicit casting to them.2057For example, structure `CD3DX12_RESOURCE_DESC` can be used to conveniently fill in structure `D3D12_RESOURCE_DESC`.20582059Similarly, this library provides a set of helper structures that aid in initialization of some of the `*_DESC` structures defined in the library.2060These are:20612062- D3D12MA::CALLOCATION_DESC, which inherits from D3D12MA::ALLOCATION_DESC.2063- D3D12MA::CPOOL_DESC, which inherits from D3D12MA::POOL_DESC.2064- D3D12MA::CVIRTUAL_BLOCK_DESC, which inherits from D3D12MA::VIRTUAL_BLOCK_DESC.2065- D3D12MA::CVIRTUAL_ALLOCATION_DESC, which inherits from D3D12MA::VIRTUAL_ALLOCATION_DESC.20662067For example, when you want to create a buffer in the `UPLAOD` heap using minimal allocation time, you can use base structures:20682069\code2070D3D12MA::ALLOCATION_DESC allocDesc;2071allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME;2072allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;2073allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_NONE;2074allocDesc.CustomPool = NULL;2075allocDesc.pPrivateData = NULL;20762077D3D12_RESOURCE_DESC resDesc;2078resDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;2079resDesc.Alignment = 0;2080resDesc.Width = myBufSize;2081resDesc.Height = 1;2082resDesc.DepthOrArraySize = 1;2083resDesc.MipLevels = 1;2084resDesc.Format = DXGI_FORMAT_UNKNOWN;2085resDesc.SampleDesc.Count = 1;2086resDesc.SampleDesc.Quality = 0;2087resDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;2088resDesc.Flags = D3D12_RESOURCE_FLAG_NONE;20892090D3D12MA::Allocation* alloc;2091ID3D12Resource* res;2092HRESULT hr = allocator->CreateResource(&allocDesc, &resDesc,2093D3D12_RESOURCE_STATE_COMMON, NULL, &alloc, IID_PPV_ARGS(&res));2094// Check hr...2095\endcode20962097Or you can use helper structs from both D3X12 library and this library to make the code shorter:20982099\code2100D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{2101D3D12_HEAP_TYPE_UPLOAD,2102D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME };21032104CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(myBufSize);21052106D3D12MA::Allocation* alloc;2107ID3D12Resource* res;2108HRESULT hr = allocator->CreateResource(&allocDesc, &resDesc,2109D3D12_RESOURCE_STATE_COMMON, NULL, &alloc, IID_PPV_ARGS(&res));2110// Check hr...2111\endcode21122113\page custom_pools Custom memory pools21142115A "pool" is a collection of memory blocks that share certain properties.2116Allocator creates 3 default pools: for `D3D12_HEAP_TYPE_DEFAULT`, `UPLOAD`, `READBACK`.2117A default pool automatically grows in size. Size of allocated blocks is also variable and managed automatically.2118Typical allocations are created in these pools. You can also create custom pools.21192120\section custom_pools_usage Usage21212122To create a custom pool, fill in structure D3D12MA::POOL_DESC and call function D3D12MA::Allocator::CreatePool2123to obtain object D3D12MA::Pool. Example:21242125\code2126POOL_DESC poolDesc = {};2127poolDesc.HeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;2128poolDesc.Flags = D3D12MA_RECOMMENDED_POOL_FLAGS;2129poolDesc.HeapFlags = D3D12MA_RECOMMENDED_HEAP_FLAGS | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;21302131Pool* pool;2132HRESULT hr = allocator->CreatePool(&poolDesc, &pool);2133\endcode21342135To allocate resources out of a custom pool, only set member D3D12MA::ALLOCATION_DESC::CustomPool.2136Example:21372138\code2139ALLOCATION_DESC allocDesc = {};2140allocDesc.CustomPool = pool;21412142D3D12_RESOURCE_DESC resDesc = ...2143Allocation* alloc;2144hr = allocator->CreateResource(&allocDesc, &resDesc,2145D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &alloc, IID_NULL, NULL);2146\endcode21472148All allocations must be released before releasing the pool.2149The pool must be released before relasing the allocator.21502151\code2152alloc->Release();2153pool->Release();2154\endcode21552156\section custom_pools_features_and_benefits Features and benefits21572158While it is recommended to use default pools whenever possible for simplicity and to give the allocator2159more opportunities for internal optimizations, custom pools may be useful in following cases:21602161- To keep some resources separate from others in memory.2162- To keep track of memory usage of just a specific group of resources. %Statistics can be queried using2163D3D12MA::Pool::CalculateStatistics.2164- To use specific size of a memory block (`ID3D12Heap`). To set it, use member D3D12MA::POOL_DESC::BlockSize.2165When set to 0, the library uses automatically determined, variable block sizes.2166- To reserve some minimum amount of memory allocated. To use it, set member D3D12MA::POOL_DESC::MinBlockCount.2167- To limit maximum amount of memory allocated. To use it, set member D3D12MA::POOL_DESC::MaxBlockCount.2168- To use extended parameters of the D3D12 memory allocation. While resources created from default pools2169can only specify `D3D12_HEAP_TYPE_DEFAULT`, `UPLOAD`, `READBACK`, a custom pool may use non-standard2170`D3D12_HEAP_PROPERTIES` (member D3D12MA::POOL_DESC::HeapProperties) and `D3D12_HEAP_FLAGS`2171(D3D12MA::POOL_DESC::HeapFlags), which is useful e.g. for cross-adapter sharing or UMA2172(see also D3D12MA::Allocator::IsUMA).21732174New versions of this library support creating **committed allocations in custom pools**.2175It is supported only when D3D12MA::POOL_DESC::BlockSize = 0.2176To use this feature, set D3D12MA::ALLOCATION_DESC::CustomPool to the pointer to your custom pool and2177D3D12MA::ALLOCATION_DESC::Flags to D3D12MA::ALLOCATION_FLAG_COMMITTED. Example:21782179\code2180ALLOCATION_DESC allocDesc = {};2181allocDesc.CustomPool = pool;2182allocDesc.Flags = ALLOCATION_FLAG_COMMITTED;21832184D3D12_RESOURCE_DESC resDesc = ...2185Allocation* alloc;2186ID3D12Resource* res;2187hr = allocator->CreateResource(&allocDesc, &resDesc,2188D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &alloc, IID_PPV_ARGS(&res));2189\endcode21902191This feature may seem unnecessary, but creating committed allocations from custom pools may be useful2192in some cases, e.g. to have separate memory usage statistics for some group of resources or to use2193extended allocation parameters, like custom `D3D12_HEAP_PROPERTIES`, which are available only in custom pools.219421952196\page optimal_allocation Optimal resource allocation21972198This library tries to automatically make optimal choices for the resources you create,2199so you don't need to care about them.2200There are some advanced features of Direct3D 12 that you may use to optimize your memory management.2201There are also some settings in %D3D12MA that you may change to alter its default behavior.2202This page provides miscellaneous advice about features of D3D12 and %D3D12MA that are2203non-essential, but may improve the stability or performance of your app.22042205\section optimal_allocation_avoiding_running_out_of_memory Avoiding running out of memory22062207When trying to allocate more memory than available in the current heap2208(e.g., video memory on the graphics card, system memory), one of few bad things can happen:22092210- The allocation (resource creation) function call can fail with `HRESULT` value other than `S_OK`.2211- The allocation may succeed, but take long time (even a significant fraction of a second).2212- Some resources are automatically demoted from video memory to system memory, degrading the app performance.2213- Even a crash of the entire graphics driver can happen, resulting in the D3D12 "device removal", which is usually2214catastrophic for the application.22152216Unfortunately, there is no way to be 100% protected against memory overcommitment.2217The best approach is to avoid allocating too much memory.22182219The full capacity of the memory can be queried using function D3D12MA::Allocator::GetMemoryCapacity.2220However, it is not recommended, because the amount of memory available to the application2221is typically smaller than the full capacity, as some portion of it is reserved by the operating system2222or used by other processes.22232224Because of this, the recommended way of fetching the **memory budget** available to the application2225is using function D3D12MA::Allocator::GetBudget.2226Preventing value D3D12MA::Budget::UsageBytes from exceeding the D3D12MA::Budget::BudgetBytes2227is probably the best we can do in trying to avoid the consequences of over-commitment.2228For more information, see also: \subpage statistics.22292230Example:22312232\code2233D3D12MA::Budget videoMemBudget = {};2234allocator->GetBudget(&videoMemBudget, NULL);22352236UINT64 freeBytes = videoMemBudget.BudgetBytes - videoMemBudget.UsageBytes;2237gameStreamingSystem->SetAvailableFreeMemory(freeBytes);2238\endcode22392240\par Implementation detail2241DXGI interface offers function `IDXGIAdapter3::QueryVideoMemoryInfo` that queries the current memory usage and budget.2242This library automatically makes use of it when available (when you use recent enough version of the DirectX SDK).2243If not, it falls back to estimating the usage and budget based on the total amount of the allocated memory2244and 80% of the full memory capacity, respectively.22452246\par Implementation detail2247Allocating large heaps and creating placed resources in them is one of the main features of this library.2248However, if allocating new such block would exceed the budget, it will automatically prefer creating the resource as committed2249to have exactly the right size, which can lower the chance of getting into trouble in case of over-commitment.22502251When creating non-essential resources, you can use D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET.2252Then, in case the allocation would exceed the budget, the library will return failure from the function2253without attempting to allocate the actual D3D12 memory.22542255It may also be a good idea to support failed resource creation.2256For non-essential resources, when function D3D12MA::Allocator::CreateResource fails with a result other than `S_OK`,2257it is worth implementing some way of recovery instead of terminating or crashing the entire app.22582259\section optimal_allocation_allocation_Performance Allocation performance22602261Creating D3D12 resources (buffers and textures) can be a time-consuming operation.2262The duration can be unpredictable, spanning from a small fraction of a millisecond to a significant fraction of a second.2263Thus, it is recommended to allocate all the memory and create all the resources needed upfront2264rather than doing it during application runtime.2265For example, a video game can try to create its resources on startup or when loading a new level.2266Of course, is is not always possible.2267For example, open-world games may require loading and unloading some graphical assets in the background (often called "streaming").22682269Creating and releasing D3D12 resources **on a separate thread** in the background may help.2270Both `ID3D12Device` and D3D12MA::Allocator objects are thread-safe, synchronized internally.2271However, cases were observed where resource creation calls like `ID3D12Device::CreateCommittedResource`2272were blocking other D3D12 calls like `ExecuteCommandLists` or `Present`2273somewhere inside the graphics driver, so hitches can happen even when using multithreading.22742275The most expensive part is typically **the allocation of a new D3D12 memory heap**.2276This library tackles this problem by automatically allocating large heaps (64 MB by default)2277and creating resources as placed inside of them.2278When a new requested resource can be placed in a free space of an existing heap and doesn't require allocating a new heap,2279this operation is typically much faster, as it only requires creating a new `ID3D12Resource` object2280and not allocating new memory.2281This is the main benefit of using %D3D12MA compared to the naive approach of using Direct3D 12 directly2282and creating each resource as committed with `CreateCommittedResource`, which would result in a separate allocation of an implicit heap every time.22832284When **a large number of small buffers** needs to be created, the overhead of creating even just separate `ID3D12Resource` objects can be significant.2285It can be avoided by creating one or few larger buffers and manually sub-allocating parts of them for specific needs.2286This library can also help with it. See section "Sub-allocating buffers" below.22872288\par Implementation detail2289The CPU performance overhead of using this library is low.2290It uses a high-quality allocation algorithm called Two-Level Segregated Fit (TLSF),2291which in most cases can find a free place for a new allocation in few steps.2292The library also doesn't perform too many CPU heap allocations.2293In may cases, the allocation happens with 0 new CPU heap allocations performed by the library.2294Even the creation of a D3D12MA::Allocation object itself doesn't typically feature an CPU allocation,2295because these objects are returned out of a dedicated memory pool.22962297Another reason for the slowness of D3D12 memory allocation is the guarantee that the **newly allocated memory is filled with zeros**.2298When creating and destroying resources placed in an existing heap, this overhead is not present,2299and the memory is not zeroed - it may contain random data left by the resource previously allocated in that place.2300In recent versions of the DirectX 12 SDK, clearing the memory of the newly created D3D12 heaps can also be disabled for the improved performance.2301%D3D12MA can use this feature when:23022303- D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED is used during the creation of the main allocator object.2304- `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED` is passed to D3D12MA::POOL_DESC::HeapFlags during the creation of a custom pool.23052306It is recommended to always use these flags.2307The downside is that when the memory is not filled with zeros, while you don't properly clear it or otherwise initialize its content before use2308(which is required by D3D12), you may observe incorrect behavior.2309This problem mostly affects render-target and depth-stencil textures.23102311When an allocation needs to be made in a performance-critical code, you can use D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME.2312In influences multiple heuristics inside the library to prefer faster allocation2313at the expense of possibly less optimal placement in the memory.23142315If the resource to be created is non-essential, while the performance is paramount,2316you can also use D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE.2317It will create the resource only if it can be placed inside and existing memory heap2318and return failure from the function if a new heap would need to be allocated,2319which should guarantee good performance of such function call.23202321\section optimal_allocation_suballocating_buffers Sub-allocating buffers23222323When a large number of small buffers needs to be created, the overhead of creating separate `ID3D12Resource` objects can be significant.2324It can also cause a significant waste of memory, as placed buffers need to be aligned to `D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT` = 64 KB by default.2325These problems can be avoided by creating one or few larger buffers and manually sub-allocating parts of them for specific needs.23262327It requires implementing a custom allocator for the data inside the buffer and using offsets to individual regions.2328When all the regions can be allocated linearly and freed all at once, implementing such allocator is trivial.2329When every region has the same size, implementing an allocator is also quite simple when using a "free list" algorithm.2330However, when regions can have different sizes and can be allocated and freed in random order,2331it requires a full allocation algorithm.2332%D3D12MA can help with it by exposing its core allocation algorithm for custom usages.2333For more details and example code, see chapter: \subpage virtual_allocator.2334It can be used for all the cases mentioned above without too much performance overhead,2335because the D3D12MA::VirtualAllocation object is just a lightweight handle.23362337When sub-allocating a buffer, you need to remember to explicitly request proper alignment required for each region.2338For example, data used as a constant buffer must be aligned to `D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT` = 256 B.23392340\section optimal_allocation_residency_priority Residency priority23412342When too much video memory is allocated, one of the things that can happen is the system2343demoting some heaps to the system memory.2344Moving data between memory pools or reaching out directly to the system memory through PCI Express bus can have large performance overhead,2345which can slow down the application, or even make the game unplayable any more.2346Unfortunately, it is not possible to fully control or prevent this demotion.2347Best thing to do is avoiding memory over-commitment.2348For more information, see section "Avoiding running out of memory" above.23492350Recent versions of DirectX 12 SDK offer function `ID3D12Device1::SetResidencyPriority` that sets a hint2351about the priority of a resource - how important it is to stay resident in the video memory.2352Setting the priority happens at the level of an entire memory heap.2353%D3D12MA offers an interface to set this priority in form of D3D12MA::POOL_DESC::ResidencyPriority parameter.2354It affects all allocations made out of the custom pool created with it, both placed inside large heaps2355and created as committed.23562357It is recommended to create a custom pool for the purpose of using high residency priority2358of all resources that are critical for the performance, especially those that are written by the GPU,2359like render-target, depth-stencil textures, UAV textures and buffers.2360It is also worth creating them as committed, so that each one will have its own implicit heap.2361This can minimize the chance that an entire large heap is demoted to system memory, degrading performance2362of all the resources placed in it.23632364Example:23652366\code2367D3D12MA::CPOOL_DESC poolDesc = D3D12MA::CPOOL_DESC{2368D3D12_HEAP_TYPE_DEFAULT,2369D3D12MA_RECOMMENDED_HEAP_FLAGS | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS };2370poolDesc.ResidencyPriority = D3D12_RESIDENCY_PRIORITY_HIGH; // !!!23712372D3D12MA::Pool* pool;2373HRESULT hr = allocator->CreatePool(&poolDesc, &pool);2374// Check hr...23752376D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{2377pool,2378ALLOCATION_FLAG_COMMITTED }; // !!!23792380CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(23811048576); // Requested buffer size.23822383D3D12MA::Allocation* alloc;2384hr = allocator->CreateResource(&allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,2385NULL, &alloc, IID_NULL, NULL);2386// Check hr...2387\endcode23882389When you have a committed allocation created, you can also set the residency priority of its resource2390using the D3D12 function:23912392\code2393D3D12MA::Allocation* committedAlloc = ...2394ID3D12Pageable* res = committedAlloc->GetResource();2395D3D12_RESIDENCY_PRIORITY priority = D3D12_RESIDENCY_PRIORITY_HIGH;2396device1->SetResidencyPriority(1, &res, &priority);2397\endcode23982399Note this is not the same as explicit eviction controlled using `ID3D12Device::Evict` and `MakeResident` functions.2400Resources evicted explicitly are illegal to access until they are made resident again,2401while the demotion described here happens automatically and only slows down the execution.24022403\section optimal_allocation_gpu_upload_heap GPU upload heap24042405Direct3D 12 offers a fixed set of memory heap types:24062407- `D3D12_HEAP_TYPE_DEFAULT`: Represents the video memory. It is available and fast to access for the GPU.2408It should be used for all resources that are written by the GPU (like render-target and depth-stencil textures,2409UAV) and resources that are frequently read by the GPU (like textures intended for sampling,2410vertex, index, and constant buffers).2411- `D3D12_HEAP_TYPE_UPLOAD`: Represents the system memory that is uncached and write-combined.2412It can be mapped and accessed by the CPU code using a pointer.2413It supports only buffers, not textures.2414It is intended for "staging buffers" that are filled by the CPU code and then used as a source of copy operations to the `DEFAULT` heap.2415It can also be accessed directly by the GPU - shaders can read from buffers created in this memory.2416- `D3D12_HEAP_TYPE_READBACK`: Represents the system memory that is cached.2417It is intended for buffers used as a destination of copy operations from the `DEFAULT` heap.24182419Note that in systems with a discrete graphics card, access to system memory is fast from the CPU code2420(like the C++ code mapping D3D12 buffers and accessing them through a pointer),2421while access to the video memory is fast from the GPU code (like shaders reading and writing buffers and textures).2422Any copy operation or direct access between these memory heap types happens through PCI Express bus, which can be relatively slow.24232424Modern systems offer a feature called **Resizable BAR (ReBAR)** that gives the CPU direct access to the full video memory.2425To be available, this feature needs to be supported by the whole hardware-software environment, including:24262427- Supporting motherboard and its UEFI.2428- Supporting graphics card and its graphics driver.2429- Supporting operating system.2430- The feature needs to be enabled in the UEFI settings. It is typically called "Above 4G Decoding" and "Resizable Bar".24312432Recent versions of DirectX 12 SDK give access to this feature in form of a new, 4th memory pool: `D3D12_HEAP_TYPE_GPU_UPLOAD`.2433Resources created in it behave logically similar to the `D3D12_HEAP_TYPE_UPLOAD` heap:24342435- They support mapping and direct access from the CPU code through a pointer.2436- The mapped memory is uncached and write-combined, so it should be only written sequentially2437(e.g., number-by-number or using `memcpy`). It shouldn't be accessed randomly or read,2438because it is extremely slow for uncached memory.2439- Only buffers are supported.2440- Those buffers can be used as a source of copy operations or directly accessed by the GPU.24412442The main difference is that resources created in the new `D3D12_HEAP_TYPE_GPU_UPLOAD` are placed in the video memory,2443while resources created in the old `D3D12_HEAP_TYPE_UPLOAD` are placed in the system memory.2444This implies which budgets are consumed by new resources allocated in those heaps.2445This also implies which operations involve transferring data through the PCI Express bus.24462447- As `D3D12_HEAP_TYPE_UPLOAD` uses the system memory, writes from the CPU code through a mapped pointer are faster,2448while copies or direct access from the GPU are slower because they need to go through PCIe.2449- As the new `D3D12_HEAP_TYPE_GPU_UPLOAD` uses the video memory,2450copies or direct access from the GPU are faster,2451while writes from the CPU code through a mapped pointer can be slower, because they need to go through PCIe.2452For maximum performance of copy operations from this heap, a graphics or compute queue should be used, not a copy queue.24532454GPU Upload Heap can be used for performance optimization of some resources that need to be written by the CPU and read by the GPU.2455It can be beneficial especially for resources that need to change frequently (often called "dynamic").24562457%D3D12MA supports GPU upload heap when recent enough version of DirectX 12 SDK is used and when the current system supports it.2458The support can be queried using function D3D12MA::Allocator::IsGPUUploadHeapSupported().2459When it returns `TRUE`, you can create resources using `D3D12_HEAP_TYPE_GPU_UPLOAD`.2460You can also just try creating such resource. Example:24612462\code2463D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{2464D3D12_HEAP_TYPE_GPU_UPLOAD }; // !!!24652466CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(24671048576); // Requested buffer size.24682469D3D12MA::Allocation* alloc;2470ID3D12Resource* res;2471hr = allocator->CreateResource(&allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,2472NULL, &alloc, IID_PPV_ARGS(&res));2473if(SUCCEEDED(hr))2474{2475// Fast path for data upload.24762477D3D12_RANGE emptyRange = {0, 0};2478void* mappedPtr = NULL;2479hr = res->Map(0, &emptyRange, &mappedPtr);2480memcpy(mappedPtr, srcData, 1048576);2481res->Unmap(0, NULL); // Optional. You can leave it persistently mapped.24822483D3D12_GPU_VIRTUAL_ADDRESS gpuva = res->GetGPUVirtualAddress();2484// Use gpuva to access the buffer on the GPU...2485}2486else if(hr == E_NOTIMPL)2487{2488// GPU Upload Heap not supported in this system.2489// Fall back to creating a staging buffer in UPLOAD and another copy in DEFAULT.24902491allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;2492// ...2493}2494else2495// Some other error code e.g., out of memory...2496\endcode24972498\section optimal_allocation_committed_vs_placed Committed versus placed resources24992500When using D3D12 API directly, there are 3 ways of creating resources:250125021. **Committed**, using function `ID3D12Device::CreateCommittedResource`.2503It creates the resource with its own memory heap, which is called an "implicit heap" and cannot be accessed directly.25042. **Placed**, using function `ID3D12Device::CreatePlacedResource`.2505A `ID3D12Heap` needs to be created beforehand using `ID3D12Device::CreateHeap`.2506Then, the resource can be created as placed inside the heap at a specific offset.25073. **Reserved**, using function `ID3D12Device::CreateReservedResource`.2508This library doesn't support them directly.25092510A naive solution would be to create all the resources as committed.2511It works, because in D3D12 there is no strict limit on the number of resources or heaps that can be created.2512However, there are certain advantages and disadvantages of using committed versus placed resources:25132514- The biggest advantage of using placed resources is the allocation performance.2515Once a heap is allocated, creating and releasing resources placed in it can be much faster than2516creating them as committed, which would involve allocating a new heap for each resource.2517- Using large number of small heaps can put an extra burden on the software stack,2518including D3D12 runtime, graphics driver, operating system, and developer tools like Radeon Memory Visualizer (RMV).2519- The advantage of committed resources is that their implicit heaps have exactly the right size,2520while creating resources as placed inside larger heaps can lead to some memory wasted because:2521- Some part of the allocated heap memory is unused.2522- After placed resources of various sizes are created and released in random order,2523gaps between remaining resources can be too small to fit new allocations.2524This is also known as "fragmentation". A solution to this problem is implementing \subpage defragmentation.2525- The alignment required by placed resources can leave gaps between them, while the driver can pack individual committed resources better.2526For details, see section "Resource alignment" below.2527- The advantage of committed resources is that they are always created with a new heap, which is initialized with zeros.2528When a resource is created as placed, the memory may contain random data left by the resource previously allocated in that place.2529When the memory is not filled with zeros, while you don't properly clear it or otherwise initialize its content before use2530(which is required by D3D12), you may observe incorrect behavior.2531On the other hand, using committed resources and having every new resource filled with zeros can leave this kind of bugs undetected.2532- Manual eviction with `ID3D12Device::Evict` and `MakeResident` functions work at the level of the entire heap,2533and so does `ID3D12Device1::SetResidencyPriority`, so creating resources as committed allows more fine-grained control2534over the eviction and residency priority of individual resources.2535- The advantage of placed resources is that they can be created in a region of a heap overlapping with some other resources.2536This approach is commonly called "aliasing".2537It can save memory, but it needs careful control over the resources that overlap in memory2538to make sure they are not used at the same time, there is an aliasing barrier issued between their usage,2539and the resource used after aliasing is correctly cleared every time.2540Committed resources don't offer this possibility, because every committed resource has its own exclusive memory heap.2541For more information, see chapter \subpage resource_aliasing.25422543When creating resources with the help of %D3D12MA using function D3D12MA::Allocator::CreateResource,2544you typically don't need to care about all this.2545The library automatically makes the choice of creating the new resource as committed or placed.2546However, in cases when you need the information or the control over this choice between committed and placed,2547the library offers facilities to do that, described below.25482549\par Implementation detail2550%D3D12MA creates large heaps (default size is 64 MB) and creates resources as placed in them.2551However, it may decide that it is required or preferred to create the specific resource as committed for many reasons, including:2552- When the resource is large (larger than half of the default heap size).2553- When allocating an entire new heap would exceed the current budget or when we are already over the budget.2554- When the resource is a very small buffer. Placed buffers need to be aligned to 64 KB by default,2555while creating them as committed can allow the driver to pack them better.2556This heuristics can be disabled for an individual resource by using D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME2557and for the entire allocator by using D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED.2558- When the resource uses non-standard flags specified via D3D12MA::ALLOCATION_DESC::ExtraHeapFlags.25592560<b>You can check whether an allocation was created as a committed resource</b> by checking if its heap is null.2561Committed resources have an implicit heap that is not directly accessible.25622563\code2564bool isCommitted = allocation->GetHeap() == NULL;2565\endcode25662567<b>You can request a new resource to be created as committed</b> by using D3D12MA::ALLOCATION_FLAG_COMMITTED.2568Note that committed resources can also be created out of \subpage custom_pools.25692570You can also request all resources to be created as committed globally for the entire allocator2571by using D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED.2572However, this contradicts the main purpose of using this library.2573It can also prevent certain other features of the library to be used.2574This flag should be used only for debugging purposes.25752576You can create a custom pool with an explicit block size by specifying non-zero D3D12MA::POOL_DESC::BlockSize.2577When doing this, all **resources created in such pool are placed** in those blocks (heaps) and never created as committed.2578Example:25792580\code2581D3D12MA::CPOOL_DESC poolDesc = D3D12MA::CPOOL_DESC{2582D3D12_HEAP_TYPE_DEFAULT,2583D3D12MA_RECOMMENDED_HEAP_FLAGS | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS };2584poolDesc.BlockSize = 100llu * 1024 * 1024; // 100 MB. Explicit BlockSize guarantees placed.25852586D3D12MA::Pool* pool;2587HRESULT hr = allocator->CreatePool(&poolDesc, &pool);2588// Check hr...25892590D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{ pool };25912592CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(259390llu * 1024 * 1024); // 90 MB25942595D3D12MA::Allocation* alloc;2596ID3D12Resource* res;2597hr = allocator->CreateResource(&allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,2598NULL, &alloc, IID_PPV_ARGS(&res));2599// Check hr...26002601// Even a large buffer like this, filling 90% of the block, was created as placed!2602assert(alloc->GetHeap() != NULL);2603\endcode26042605<b>You can request a new resource to be created as placed</b> by using D3D12MA::ALLOCATION_FLAG_CAN_ALIAS.2606This is required especially if you plan to create another resource in the same region of memory, aliasing with your resource -2607hence the name of this flag.26082609Note D3D12MA::ALLOCATION_FLAG_CAN_ALIAS can be even combined with D3D12MA::ALLOCATION_FLAG_COMMITTED.2610In this case, the resource is not created as committed, but it is also not placed as part of a larger heap.2611What happens instead is that a new heap is created with the exact size required for the resource,2612and the resource is created in it, placed at offset 0.26132614\section optimal_allocation_resource_alignment Resource alignment26152616Certain types of resources require certain alignment in memory.2617An alignment is a requirement for the address or offset to the beginning of the resource to be a multiply of some value, which is always a power of 2.2618For committed resources, the problem is non-existent, because committed resources have their own implicit heaps2619where they are created at offset 0, which meets any alignment requirement.2620For placed resources, %D3D12MA takes care of the alignment automatically.26212622\par Implementation detail2623Default alignment required MSAA textures is `D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT` = 4 MB.2624Default alignment required for buffers and other textures is `D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT` = 64 KB.26252626Because the alignment required for buffers is 64 KB, **small buffers** can waste a lot of memory in between when created as placed.2627When such small buffers are created as committed, some graphics drivers are able to pack them better.2628%D3D12MA automatically takes advantage of this by preferring to create small buffers as committed.2629This heuristics is enabled by default. It is also a tradeoff - it can make the allocation of these buffers slower.2630It can be disabled for an individual resource by using D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME2631and for the entire allocator by using D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED.26322633For certain textures that meet a complex set of requirements, special **"small alignment"** can be applied.2634Details can be found in Microsoft documentation of the `D3D12_RESOURCE_DESC` structure.2635For MSAA textures, the small alignment is `D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT` = 64 KB.2636For other textures, the small alignment is `D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT` = 4 KB.2637%D3D12MA uses this feature automatically.2638Detailed behavior can be disabled or controlled by predefining macro #D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT.26392640D3D12 also has a concept of **alignment of the entire heap**, passed through `D3D12_HEAP_DESC::Alignment`.2641This library automatically sets the alignment as small as possible.2642Unfortunately, any heap that has a chance of hosting an MSAA texture needs to have the alignment set to 4 MB.2643This problem can be overcome by passing D3D12MA::ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED on the creation of the main allocator object2644and D3D12MA::POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED on the creation of any custom heap that supports textures, not only buffers.2645With those flags, the alignment of the heaps created by %D3D12MA can be lower, but any MSAA textures are created as committed.2646You should always use these flags in your code unless you really need to create some MSAA textures as placed.26472648\page defragmentation Defragmentation26492650Interleaved allocations and deallocations of many objects of varying size can2651cause fragmentation over time, which can lead to a situation where the library is unable2652to find a continuous range of free memory for a new allocation despite there is2653enough free space, just scattered across many small free ranges between existing2654allocations.26552656To mitigate this problem, you can use defragmentation feature.2657It doesn't happen automatically though and needs your cooperation,2658because %D3D12MA is a low level library that only allocates memory.2659It cannot recreate buffers and textures in a new place as it doesn't remember the contents of `D3D12_RESOURCE_DESC` structure.2660It cannot copy their contents as it doesn't record any commands to a command list.26612662Example:26632664\code2665D3D12MA::DEFRAGMENTATION_DESC defragDesc = {};2666defragDesc.Flags = D3D12MA::DEFRAGMENTATION_FLAG_ALGORITHM_FAST;26672668D3D12MA::DefragmentationContext* defragCtx;2669allocator->BeginDefragmentation(&defragDesc, &defragCtx);26702671for(;;)2672{2673D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO pass;2674HRESULT hr = defragCtx->BeginPass(&pass);2675if(hr == S_OK)2676break;2677else if(hr != S_FALSE)2678// Handle error...26792680for(UINT i = 0; i < pass.MoveCount; ++i)2681{2682// Inspect pass.pMoves[i].pSrcAllocation, identify what buffer/texture it represents.2683MyEngineResourceData* resData = (MyEngineResourceData*)pMoves[i].pSrcAllocation->GetPrivateData();26842685// Recreate this buffer/texture as placed at pass.pMoves[i].pDstTmpAllocation.2686D3D12_RESOURCE_DESC resDesc = ...2687ID3D12Resource* newRes;2688hr = device->CreatePlacedResource(2689pass.pMoves[i].pDstTmpAllocation->GetHeap(),2690pass.pMoves[i].pDstTmpAllocation->GetOffset(), &resDesc,2691D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&newRes));2692// Check hr...26932694// Store new resource in the pDstTmpAllocation.2695pass.pMoves[i].pDstTmpAllocation->SetResource(newRes);26962697// Copy its content to the new place.2698cmdList->CopyResource(2699pass.pMoves[i].pDstTmpAllocation->GetResource(),2700pass.pMoves[i].pSrcAllocation->GetResource());2701}27022703// Make sure the copy commands finished executing.2704cmdQueue->ExecuteCommandLists(...);2705// ...2706WaitForSingleObject(fenceEvent, INFINITE);27072708// Update appropriate descriptors to point to the new places...27092710hr = defragCtx->EndPass(&pass);2711if(hr == S_OK)2712break;2713else if(hr != S_FALSE)2714// Handle error...2715}27162717defragCtx->Release();2718\endcode27192720Although functions like D3D12MA::Allocator::CreateResource()2721create an allocation and a buffer/texture at once, these are just a shortcut for2722allocating memory and creating a placed resource.2723Defragmentation works on memory allocations only. You must handle the rest manually.2724Defragmentation is an iterative process that should repreat "passes" as long as related functions2725return `S_FALSE` not `S_OK`.2726In each pass:272727281. D3D12MA::DefragmentationContext::BeginPass() function call:2729- Calculates and returns the list of allocations to be moved in this pass.2730Note this can be a time-consuming process.2731- Reserves destination memory for them by creating temporary destination allocations2732that you can query for their `ID3D12Heap` + offset using methods like D3D12MA::Allocation::GetHeap().27332. Inside the pass, **you should**:2734- Inspect the returned list of allocations to be moved.2735- Create new buffers/textures as placed at the returned destination temporary allocations.2736- Copy data from source to destination resources if necessary.2737- Store the pointer to the new resource in the temporary destination allocation.27383. D3D12MA::DefragmentationContext::EndPass() function call:2739- Frees the source memory reserved for the allocations that are moved.2740- Modifies source D3D12MA::Allocation objects that are moved to point to the destination reserved memory2741and destination resource, while source resource is released.2742- Frees `ID3D12Heap` blocks that became empty.27432744Defragmentation algorithm tries to move all suitable allocations.2745You can, however, refuse to move some of them inside a defragmentation pass, by setting2746`pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.2747This is not recommended and may result in suboptimal packing of the allocations after defragmentation.2748If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.27492750Inside a pass, for each allocation that should be moved:27512752- You should copy its data from the source to the destination place by calling e.g. `CopyResource()`.2753- You need to make sure these commands finished executing before the source buffers/textures are released by D3D12MA::DefragmentationContext::EndPass().2754- If a resource doesn't contain any meaningful data, e.g. it is a transient render-target texture to be cleared,2755filled, and used temporarily in each rendering frame, you can just recreate this texture2756without copying its data.2757- If the resource is in `D3D12_HEAP_TYPE_READBACK` memory, you can copy its data on the CPU2758using `memcpy()`.2759- If you cannot move the allocation, you can set `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.2760This will cancel the move.2761- D3D12MA::DefragmentationContext::EndPass() will then free the destination memory2762not the source memory of the allocation, leaving it unchanged.2763- If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time),2764you can set `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY.2765- D3D12MA::DefragmentationContext::EndPass() will then free both source and destination memory, and will destroy the source D3D12MA::Allocation object.27662767You can defragment a specific custom pool by calling D3D12MA::Pool::BeginDefragmentation2768or all the default pools by calling D3D12MA::Allocator::BeginDefragmentation (like in the example above).27692770Defragmentation is always performed in each pool separately.2771Allocations are never moved between different heap types.2772The size of the destination memory reserved for a moved allocation is the same as the original one.2773Alignment of an allocation as it was determined using `GetResourceAllocationInfo()` is also respected after defragmentation.2774Buffers/textures should be recreated with the same `D3D12_RESOURCE_DESC` parameters as the original ones.27752776You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved2777in each pass, e.g. to call it in sync with render frames and not to experience too big hitches.2778See members: D3D12MA::DEFRAGMENTATION_DESC::MaxBytesPerPass, D3D12MA::DEFRAGMENTATION_DESC::MaxAllocationsPerPass.27792780<b>Thread safety:</b>2781It is safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and %D3D12MA2782usage, possibly from multiple threads, with the exception that allocations2783returned in D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO::pMoves shouldn't be released until the defragmentation pass is ended.2784During the call to D3D12MA::DefragmentationContext::BeginPass(), any operations on the memory pool2785affected by the defragmentation are blocked by a mutex.27862787What it means in practice is that you shouldn't free any allocations from the defragmented pool2788since the moment a call to `BeginPass` begins. Otherwise, a thread performing the `allocation->Release()`2789would block for the time `BeginPass` executes and then free the allocation when it finishes, while the allocation2790could have ended up on the list of allocations to move.2791A solution to freeing allocations during defragmentation is to find such allocation on the list2792`pass.pMoves[i]` and set its operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY instead of2793calling `allocation->Release()`, or simply deferring the release to the time after defragmentation finished.27942795<b>Mapping</b> is out of scope of this library and so it is not preserved after an allocation is moved during defragmentation.2796You need to map the new resource yourself if needed.27972798\note Defragmentation is not supported in custom pools created with D3D12MA::POOL_FLAG_ALGORITHM_LINEAR.279928002801\page statistics Statistics28022803This library contains several functions that return information about its internal state,2804especially the amount of memory allocated from D3D12.28052806\section statistics_numeric_statistics Numeric statistics28072808If you need to obtain basic statistics about memory usage per memory segment group, together with current budget,2809you can call function D3D12MA::Allocator::GetBudget() and inspect structure D3D12MA::Budget.2810This is useful to keep track of memory usage and stay withing budget.2811Example:28122813\code2814D3D12MA::Budget localBudget;2815allocator->GetBudget(&localBudget, NULL);28162817printf("My GPU memory currently has %u allocations taking %llu B,\n",2818localBudget.Statistics.AllocationCount,2819localBudget.Statistics.AllocationBytes);2820printf("allocated out of %u D3D12 memory heaps taking %llu B,\n",2821localBudget.Statistics.BlockCount,2822localBudget.Statistics.BlockBytes);2823printf("D3D12 reports total usage %llu B with budget %llu B.\n",2824localBudget.UsageBytes,2825localBudget.BudgetBytes);2826\endcode28272828You can query for more detailed statistics per heap type, memory segment group, and totals,2829including minimum and maximum allocation size and unused range size,2830by calling function D3D12MA::Allocator::CalculateStatistics() and inspecting structure D3D12MA::TotalStatistics.2831This function is slower though, as it has to traverse all the internal data structures,2832so it should be used only for debugging purposes.28332834You can query for statistics of a custom pool using function D3D12MA::Pool::GetStatistics()2835or D3D12MA::Pool::CalculateStatistics().28362837You can query for information about a specific allocation using functions of the D3D12MA::Allocation class,2838e.g. `GetSize()`, `GetOffset()`, `GetHeap()`.28392840\section statistics_json_dump JSON dump28412842You can dump internal state of the allocator to a string in JSON format using function D3D12MA::Allocator::BuildStatsString().2843The result is guaranteed to be correct JSON.2844It uses Windows Unicode (UTF-16) encoding.2845Any strings provided by user (see D3D12MA::Allocation::SetName())2846are copied as-is and properly escaped for JSON.2847It must be freed using function D3D12MA::Allocator::FreeStatsString().28482849The format of this JSON string is not part of official documentation of the library,2850but it will not change in backward-incompatible way without increasing library major version number2851and appropriate mention in changelog.28522853The JSON string contains all the data that can be obtained using D3D12MA::Allocator::CalculateStatistics().2854It can also contain detailed map of allocated memory blocks and their regions -2855free and occupied by allocations.2856This allows e.g. to visualize the memory or assess fragmentation.285728582859\page resource_aliasing Resource aliasing (overlap)28602861New explicit graphics APIs (Vulkan and Direct3D 12), thanks to manual memory2862management, give an opportunity to alias (overlap) multiple resources in the2863same region of memory - a feature not available in the old APIs (Direct3D 11, OpenGL).2864It can be useful to save video memory, but it must be used with caution.28652866For example, if you know the flow of your whole render frame in advance, you2867are going to use some intermediate textures or buffers only during a small range of render passes,2868and you know these ranges don't overlap in time, you can create these resources in2869the same place in memory, even if they have completely different parameters (width, height, format etc.).2870287128722873Such scenario is possible using D3D12MA, but you need to create your resources2874using special function D3D12MA::Allocator::CreateAliasingResource.2875Before that, you need to allocate memory with parameters calculated using formula:28762877- allocation size = max(size of each resource)2878- allocation alignment = max(alignment of each resource)28792880Following example shows two different textures created in the same place in memory,2881allocated to fit largest of them.28822883\code2884D3D12_RESOURCE_DESC resDesc1 = {};2885resDesc1.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;2886resDesc1.Alignment = 0;2887resDesc1.Width = 1920;2888resDesc1.Height = 1080;2889resDesc1.DepthOrArraySize = 1;2890resDesc1.MipLevels = 1;2891resDesc1.Format = DXGI_FORMAT_R8G8B8A8_UNORM;2892resDesc1.SampleDesc.Count = 1;2893resDesc1.SampleDesc.Quality = 0;2894resDesc1.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;2895resDesc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;28962897D3D12_RESOURCE_DESC resDesc2 = {};2898resDesc2.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;2899resDesc2.Alignment = 0;2900resDesc2.Width = 1024;2901resDesc2.Height = 1024;2902resDesc2.DepthOrArraySize = 1;2903resDesc2.MipLevels = 0;2904resDesc2.Format = DXGI_FORMAT_R8G8B8A8_UNORM;2905resDesc2.SampleDesc.Count = 1;2906resDesc2.SampleDesc.Quality = 0;2907resDesc2.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;2908resDesc2.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;29092910const D3D12_RESOURCE_ALLOCATION_INFO allocInfo1 =2911device->GetResourceAllocationInfo(0, 1, &resDesc1);2912const D3D12_RESOURCE_ALLOCATION_INFO allocInfo2 =2913device->GetResourceAllocationInfo(0, 1, &resDesc2);29142915D3D12_RESOURCE_ALLOCATION_INFO finalAllocInfo = {};2916finalAllocInfo.Alignment = std::max(allocInfo1.Alignment, allocInfo2.Alignment);2917finalAllocInfo.SizeInBytes = std::max(allocInfo1.SizeInBytes, allocInfo2.SizeInBytes);29182919D3D12MA::ALLOCATION_DESC allocDesc = {};2920allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;2921allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;29222923D3D12MA::Allocation* alloc;2924hr = allocator->AllocateMemory(&allocDesc, &finalAllocInfo, &alloc);2925assert(alloc != NULL && alloc->GetHeap() != NULL);29262927ID3D12Resource* res1;2928hr = allocator->CreateAliasingResource(2929alloc,29300, // AllocationLocalOffset2931&resDesc1,2932D3D12_RESOURCE_STATE_COMMON,2933NULL, // pOptimizedClearValue2934IID_PPV_ARGS(&res1));29352936ID3D12Resource* res2;2937hr = allocator->CreateAliasingResource(2938alloc,29390, // AllocationLocalOffset2940&resDesc2,2941D3D12_RESOURCE_STATE_COMMON,2942NULL, // pOptimizedClearValue2943IID_PPV_ARGS(&res2));29442945// You can use res1 and res2, but not at the same time!29462947res2->Release();2948res1->Release();2949alloc->Release();2950\endcode29512952Remember that using resouces that alias in memory requires proper synchronization.2953You need to issue a special barrier of type `D3D12_RESOURCE_BARRIER_TYPE_ALIASING`.2954You also need to treat a resource after aliasing as uninitialized - containing garbage data.2955For example, if you use `res1` and then want to use `res2`, you need to first initialize `res2`2956using either Clear, Discard, or Copy to the entire resource.29572958Additional considerations:29592960- D3D12 also allows to interpret contents of memory between aliasing resources consistently in some cases,2961which is called "data inheritance". For details, see2962Microsoft documentation chapter "Memory Aliasing and Data Inheritance".2963- You can create more complex layout where different textures and buffers are bound2964at different offsets inside one large allocation. For example, one can imagine2965a big texture used in some render passes, aliasing with a set of many small buffers2966used in some further passes. To bind a resource at non-zero offset of an allocation,2967call D3D12MA::Allocator::CreateAliasingResource with appropriate value of `AllocationLocalOffset` parameter.2968- Resources of the three categories: buffers, textures with `RENDER_TARGET` or `DEPTH_STENCIL` flags, and all other textures,2969can be placed in the same memory only when `allocator->GetD3D12Options().ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2`.2970Otherwise they must be placed in different memory heap types, and thus aliasing them is not possible.297129722973\page linear_algorithm Linear allocation algorithm29742975Each D3D12 memory block managed by this library has accompanying metadata that2976keeps track of used and unused regions. By default, the metadata structure and2977algorithm tries to find best place for new allocations among free regions to2978optimize memory usage. This way you can allocate and free objects in any order.2979298029812982Sometimes there is a need to use simpler, linear allocation algorithm. You can2983create custom pool that uses such algorithm by adding flag2984D3D12MA::POOL_FLAG_ALGORITHM_LINEAR to D3D12MA::POOL_DESC::Flags while creating2985D3D12MA::Pool object. Then an alternative metadata management is used. It always2986creates new allocations after last one and doesn't reuse free regions after2987allocations freed in the middle. It results in better allocation performance and2988less memory consumed by metadata.2989299029912992With this one flag, you can create a custom pool that can be used in many ways:2993free-at-once, stack, double stack, and ring buffer. See below for details.2994You don't need to specify explicitly which of these options you are going to use - it is detected automatically.29952996\section linear_algorithm_free_at_once Free-at-once29972998In a pool that uses linear algorithm, you still need to free all the allocations2999individually by calling `allocation->Release()`. You can free3000them in any order. New allocations are always made after last one - free space3001in the middle is not reused. However, when you release all the allocation and3002the pool becomes empty, allocation starts from the beginning again. This way you3003can use linear algorithm to speed up creation of allocations that you are going3004to release all at once.3005300630073008This mode is also available for pools created with D3D12MA::POOL_DESC::MaxBlockCount3009value that allows multiple memory blocks.30103011\section linear_algorithm_stack Stack30123013When you free an allocation that was created last, its space can be reused.3014Thanks to this, if you always release allocations in the order opposite to their3015creation (LIFO - Last In First Out), you can achieve behavior of a stack.3016301730183019This mode is also available for pools created with D3D12MA::POOL_DESC::MaxBlockCount3020value that allows multiple memory blocks.30213022\section linear_algorithm_double_stack Double stack30233024The space reserved by a custom pool with linear algorithm may be used by two3025stacks:30263027- First, default one, growing up from offset 0.3028- Second, "upper" one, growing down from the end towards lower offsets.30293030To make allocation from the upper stack, add flag D3D12MA::ALLOCATION_FLAG_UPPER_ADDRESS3031to D3D12MA::ALLOCATION_DESC::Flags.3032303330343035Double stack is available only in pools with one memory block -3036D3D12MA::POOL_DESC::MaxBlockCount must be 1. Otherwise behavior is undefined.30373038When the two stacks' ends meet so there is not enough space between them for a3039new allocation, such allocation fails with usual `E_OUTOFMEMORY` error.30403041\section linear_algorithm_ring_buffer Ring buffer30423043When you free some allocations from the beginning and there is not enough free space3044for a new one at the end of a pool, allocator's "cursor" wraps around to the3045beginning and starts allocation there. Thanks to this, if you always release3046allocations in the same order as you created them (FIFO - First In First Out),3047you can achieve behavior of a ring buffer / queue.3048304930503051Ring buffer is available only in pools with one memory block -3052D3D12MA::POOL_DESC::MaxBlockCount must be 1. Otherwise behavior is undefined.30533054\section linear_algorithm_additional_considerations Additional considerations30553056Linear algorithm can also be used with \ref virtual_allocator.3057See flag D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR.305830593060\page virtual_allocator Virtual allocator30613062As an extra feature, the core allocation algorithm of the library is exposed through a simple and convenient API of "virtual allocator".3063It doesn't allocate any real GPU memory. It just keeps track of used and free regions of a "virtual block".3064You can use it to allocate your own memory or other objects, even completely unrelated to D3D12.3065A common use case is sub-allocation of pieces of one large GPU buffer.3066Another suggested use case is allocating descriptors in a `ID3D12DescriptorHeap`.30673068\section virtual_allocator_creating_virtual_block Creating virtual block30693070To use this functionality, there is no main "allocator" object.3071You don't need to have D3D12MA::Allocator object created.3072All you need to do is to create a separate D3D12MA::VirtualBlock object for each block of memory you want to be managed by the allocator:30733074-# Fill in D3D12MA::ALLOCATOR_DESC structure.3075-# Call D3D12MA::CreateVirtualBlock. Get new D3D12MA::VirtualBlock object.30763077Example:30783079\code3080D3D12MA::VIRTUAL_BLOCK_DESC blockDesc = {};3081blockDesc.Size = 1048576; // 1 MB30823083D3D12MA::VirtualBlock *block;3084HRESULT hr = CreateVirtualBlock(&blockDesc, &block);3085\endcode30863087\section virtual_allocator_making_virtual_allocations Making virtual allocations30883089D3D12MA::VirtualBlock object contains internal data structure that keeps track of free and occupied regions3090using the same code as the main D3D12 memory allocator.3091A single allocation is identified by a lightweight structure D3D12MA::VirtualAllocation.3092You will also likely want to know the offset at which the allocation was made in the block.30933094In order to make an allocation:30953096-# Fill in D3D12MA::VIRTUAL_ALLOCATION_DESC structure.3097-# Call D3D12MA::VirtualBlock::Allocate. Get new D3D12MA::VirtualAllocation value that identifies the allocation.30983099Example:31003101\code3102D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};3103allocDesc.Size = 4096; // 4 KB31043105D3D12MA::VirtualAllocation alloc;3106UINT64 allocOffset;3107hr = block->Allocate(&allocDesc, &alloc, &allocOffset);3108if(SUCCEEDED(hr))3109{3110// Use the 4 KB of your memory starting at allocOffset.3111}3112else3113{3114// Allocation failed - no space for it could be found. Handle this error!3115}3116\endcode31173118\section virtual_allocator_deallocation Deallocation31193120When no longer needed, an allocation can be freed by calling D3D12MA::VirtualBlock::FreeAllocation.31213122When whole block is no longer needed, the block object can be released by calling `block->Release()`.3123All allocations must be freed before the block is destroyed, which is checked internally by an assert.3124However, if you don't want to call `block->FreeAllocation` for each allocation, you can use D3D12MA::VirtualBlock::Clear to free them all at once -3125a feature not available in normal D3D12 memory allocator.31263127Example:31283129\code3130block->FreeAllocation(alloc);3131block->Release();3132\endcode31333134\section virtual_allocator_allocation_parameters Allocation parameters31353136You can attach a custom pointer to each allocation by using D3D12MA::VirtualBlock::SetAllocationPrivateData.3137Its default value is `NULL`.3138It can be used to store any data that needs to be associated with that allocation - e.g. an index, a handle, or a pointer to some3139larger data structure containing more information. Example:31403141\code3142struct CustomAllocData3143{3144std::string m_AllocName;3145};3146CustomAllocData* allocData = new CustomAllocData();3147allocData->m_AllocName = "My allocation 1";3148block->SetAllocationPrivateData(alloc, allocData);3149\endcode31503151The pointer can later be fetched, along with allocation offset and size, by passing the allocation handle to function3152D3D12MA::VirtualBlock::GetAllocationInfo and inspecting returned structure D3D12MA::VIRTUAL_ALLOCATION_INFO.3153If you allocated a new object to be used as the custom pointer, don't forget to delete that object before freeing the allocation!3154Example:31553156\code3157VIRTUAL_ALLOCATION_INFO allocInfo;3158block->GetAllocationInfo(alloc, &allocInfo);3159delete (CustomAllocData*)allocInfo.pPrivateData;31603161block->FreeAllocation(alloc);3162\endcode31633164\section virtual_allocator_alignment_and_units Alignment and units31653166It feels natural to express sizes and offsets in bytes.3167If an offset of an allocation needs to be aligned to a multiply of some number (e.g. 4 bytes), you can fill optional member3168D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment to request it. Example:31693170\code3171D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};3172allocDesc.Size = 4096; // 4 KB3173allocDesc.Alignment = 4; // Returned offset must be a multiply of 4 B31743175D3D12MA::VirtualAllocation alloc;3176UINT64 allocOffset;3177hr = block->Allocate(&allocDesc, &alloc, &allocOffset);3178\endcode31793180Alignments of different allocations made from one block may vary.3181However, if all alignments and sizes are always multiply of some size e.g. 4 B or `sizeof(MyDataStruct)`,3182you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes.3183It might be more convenient, but you need to make sure to use this new unit consistently in all the places:31843185- D3D12MA::VIRTUAL_BLOCK_DESC::Size3186- D3D12MA::VIRTUAL_ALLOCATION_DESC::Size and D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment3187- Using offset returned by D3D12MA::VirtualBlock::Allocate and D3D12MA::VIRTUAL_ALLOCATION_INFO::Offset31883189\section virtual_allocator_statistics Statistics31903191You can obtain brief statistics of a virtual block using D3D12MA::VirtualBlock::GetStatistics().3192The function fills structure D3D12MA::Statistics - same as used by the normal D3D12 memory allocator.3193Example:31943195\code3196D3D12MA::Statistics stats;3197block->GetStatistics(&stats);3198printf("My virtual block has %llu bytes used by %u virtual allocations\n",3199stats.AllocationBytes, stats.AllocationCount);3200\endcode32013202More detailed statistics can be obtained using function D3D12MA::VirtualBlock::CalculateStatistics(),3203but they are slower to calculate.32043205You can also request a full list of allocations and free regions as a string in JSON format by calling3206D3D12MA::VirtualBlock::BuildStatsString.3207Returned string must be later freed using D3D12MA::VirtualBlock::FreeStatsString.3208The format of this string may differ from the one returned by the main D3D12 allocator, but it is similar.32093210\section virtual_allocator_additional_considerations Additional considerations32113212Alternative, linear algorithm can be used with virtual allocator - see flag3213D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR and documentation: \ref linear_algorithm.32143215Note that the "virtual allocator" functionality is implemented on a level of individual memory blocks.3216Keeping track of a whole collection of blocks, allocating new ones when out of free space,3217deleting empty ones, and deciding which one to try first for a new allocation must be implemented by the user.321832193220\page configuration Configuration32213222Please check file `D3D12MemAlloc.cpp` lines between "Configuration Begin" and3223"Configuration End" to find macros that you can define to change the behavior of3224the library, primarily for debugging purposes.32253226\section custom_memory_allocator Custom CPU memory allocator32273228If you use custom allocator for CPU memory rather than default C++ operator `new`3229and `delete` or `malloc` and `free` functions, you can make this library using3230your allocator as well by filling structure D3D12MA::ALLOCATION_CALLBACKS and3231passing it as optional member D3D12MA::ALLOCATOR_DESC::pAllocationCallbacks.3232Functions pointed there will be used by the library to make any CPU-side3233allocations. Example:32343235\code3236#include <malloc.h>32373238void* CustomAllocate(size_t Size, size_t Alignment, void* pPrivateData)3239{3240void* memory = _aligned_malloc(Size, Alignment);3241// Your extra bookkeeping here...3242return memory;3243}32443245void CustomFree(void* pMemory, void* pPrivateData)3246{3247// Your extra bookkeeping here...3248_aligned_free(pMemory);3249}32503251...32523253D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};3254allocationCallbacks.pAllocate = &CustomAllocate;3255allocationCallbacks.pFree = &CustomFree;32563257D3D12MA::ALLOCATOR_DESC allocatorDesc = {};3258allocatorDesc.pDevice = device;3259allocatorDesc.pAdapter = adapter;3260allocatorDesc.Flags = D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS;3261allocatorDesc.pAllocationCallbacks = &allocationCallbacks;32623263D3D12MA::Allocator* allocator;3264HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);3265// Check hr...3266\endcode326732683269\section debug_margins Debug margins32703271By default, allocations are laid out in memory blocks next to each other if possible3272(considering required alignment returned by `ID3D12Device::GetResourceAllocationInfo`).3273327432753276Define macro `D3D12MA_DEBUG_MARGIN` to some non-zero value (e.g. 16) inside "D3D12MemAlloc.cpp"3277to enforce specified number of bytes as a margin after every allocation.3278327932803281If your bug goes away after enabling margins, it means it may be caused by memory3282being overwritten outside of allocation boundaries. It is not 100% certain though.3283Change in application behavior may also be caused by different order and distribution3284of allocations across memory blocks after margins are applied.32853286Margins work with all memory heap types.32873288Margin is applied only to placed allocations made out of memory heaps and not to committed3289allocations, which have their own, implicit memory heap of specific size.3290It is thus not applied to allocations made using D3D12MA::ALLOCATION_FLAG_COMMITTED flag3291or those automatically decided to put into committed allocations, e.g. due to its large size.32923293Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space.32943295Note that enabling margins increases memory usage and fragmentation.32963297Margins do not apply to \ref virtual_allocator.329832993300\page general_considerations General considerations33013302\section general_considerations_thread_safety Thread safety33033304- The library has no global state, so separate D3D12MA::Allocator objects can be used independently.3305In typical applications there should be no need to create multiple such objects though - one per `ID3D12Device` is enough.3306- All calls to methods of D3D12MA::Allocator class are safe to be made from multiple3307threads simultaneously because they are synchronized internally when needed.3308- When the allocator is created with D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED,3309calls to methods of D3D12MA::Allocator class must be made from a single thread or synchronized by the user.3310Using this flag may improve performance.3311- D3D12MA::VirtualBlock is not safe to be used from multiple threads simultaneously.33123313\section general_considerations_versioning_and_compatibility Versioning and compatibility33143315The library uses [**Semantic Versioning**](https://semver.org/),3316which means version numbers follow convention: Major.Minor.Patch (e.g. 2.3.0), where:33173318- Incremented Patch version means a release is backward- and forward-compatible,3319introducing only some internal improvements, bug fixes, optimizations etc.3320or changes that are out of scope of the official API described in this documentation.3321- Incremented Minor version means a release is backward-compatible,3322so existing code that uses the library should continue to work, while some new3323symbols could have been added: new structures, functions, new values in existing3324enums and bit flags, new structure members, but not new function parameters.3325- Incrementing Major version means a release could break some backward compatibility.33263327All changes between official releases are documented in file "CHANGELOG.md".33283329\warning Backward compatiblity is considered on the level of C++ source code, not binary linkage.3330Adding new members to existing structures is treated as backward compatible if initializing3331the new members to binary zero results in the old behavior.3332You should always fully initialize all library structures to zeros and not rely on their3333exact binary size.33343335\section general_considerations_features_not_supported Features not supported33363337Features deliberately excluded from the scope of this library:33383339- **Descriptor allocation.** Although also called "heaps", objects that represent3340descriptors are separate part of the D3D12 API from buffers and textures.3341You can still use \ref virtual_allocator to manage descriptors and their ranges inside a descriptor heap.3342- **Support for reserved (tiled) resources.** We don't recommend using them.3343- Support for `ID3D12Device::Evict` and `MakeResident`. We don't recommend using them.3344You can call them on the D3D12 objects manually.3345Plese keep in mind, however, that eviction happens on the level of entire `ID3D12Heap` memory blocks3346and not individual buffers or textures which may be placed inside them.3347- **Handling CPU memory allocation failures.** When dynamically creating small C++3348objects in CPU memory (not the GPU memory), allocation failures are not3349handled gracefully, because that would complicate code significantly and3350is usually not needed in desktop PC applications anyway.3351Success of an allocation is just checked with an assert.3352- **Code free of any compiler warnings.**3353There are many preprocessor macros that make some variables unused, function parameters unreferenced,3354or conditional expressions constant in some configurations.3355The code of this library should not be bigger or more complicated just to silence these warnings.3356It is recommended to disable such warnings instead.3357- This is a C++ library. **Bindings or ports to any other programming languages** are welcome as external projects but3358are not going to be included into this repository.3359*/336033613362