• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #pragma once
24 
25 /** \mainpage D3D12 Memory Allocator
26 
27 <b>Version 2.0.0-development</b> (2020-07-16)
28 
29 Copyright (c) 2019-2020 Advanced Micro Devices, Inc. All rights reserved. \n
30 License: MIT
31 
32 Documentation of all members: D3D12MemAlloc.h
33 
34 \section main_table_of_contents Table of contents
35 
36 - <b>User guide</b>
37     - \subpage quick_start
38         - [Project setup](@ref quick_start_project_setup)
39         - [Creating resources](@ref quick_start_creating_resources)
40         - [Mapping memory](@ref quick_start_mapping_memory)
41     - \subpage resource_aliasing
42     - \subpage reserving_memory
43     - \subpage virtual_allocator
44 - \subpage configuration
45   - [Custom CPU memory allocator](@ref custom_memory_allocator)
46 - \subpage general_considerations
47   - [Thread safety](@ref general_considerations_thread_safety)
48   - [Future plans](@ref general_considerations_future_plans)
49   - [Features not supported](@ref general_considerations_features_not_supported)
50 
51 \section main_see_also See also
52 
53 - [Product page on GPUOpen](https://gpuopen.com/gaming-product/d3d12-memory-allocator/)
54 - [Source repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator)
55 
56 
57 \page quick_start Quick start
58 
59 \section quick_start_project_setup Project setup and initialization
60 
61 This is a small, standalone C++ library. It consists of a pair of 2 files:
62 "%D3D12MemAlloc.h" header file with public interface and "D3D12MemAlloc.cpp" with
63 internal implementation. The only external dependencies are WinAPI, Direct3D 12,
64 and parts of C/C++ standard library (but STL containers, exceptions, or RTTI are
65 not used).
66 
67 The library is developed and tested using Microsoft Visual Studio 2019, but it
68 should work with other compilers as well. It is designed for 64-bit code.
69 
70 To use the library in your project:
71 
72 (1.) Copy files `D3D12MemAlloc.cpp`, `%D3D12MemAlloc.h` to your project.
73 
74 (2.) Make `D3D12MemAlloc.cpp` compiling as part of the project, as C++ code.
75 
76 (3.) Include library header in each CPP file that needs to use the library.
77 
78 \code
79 #include "D3D12MemAlloc.h"
80 \endcode
81 
82 (4.) Right after you created `ID3D12Device`, fill D3D12MA::ALLOCATOR_DESC
83 structure and call function D3D12MA::CreateAllocator to create the main
84 D3D12MA::Allocator object.
85 
86 Please note that all symbols of the library are declared inside #D3D12MA namespace.
87 
88 \code
89 IDXGIAdapter* adapter = (...)
90 ID3D12Device* device = (...)
91 
92 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
93 allocatorDesc.pDevice = device;
94 allocatorDesc.pAdapter = adapter;
95 
96 D3D12MA::Allocator* allocator;
97 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
98 \endcode
99 
100 (5.) Right before destroying the D3D12 device, destroy the allocator object.
101 
102 Please note that objects of this library must be destroyed by calling `Release`
103 method (despite they are not COM interfaces and no reference counting is involved).
104 
105 \code
106 allocator->Release();
107 \endcode
108 
109 
110 \section quick_start_creating_resources Creating resources
111 
112 To use the library for creating resources (textures and buffers), call method
113 D3D12MA::Allocator::CreateResource in the place where you would previously call
114 `ID3D12Device::CreateCommittedResource`.
115 
116 The function has similar syntax, but it expects structure D3D12MA::ALLOCATION_DESC
117 to be passed along with `D3D12_RESOURCE_DESC` and other parameters for created
118 resource. This structure describes parameters of the desired memory allocation,
119 including choice of `D3D12_HEAP_TYPE`.
120 
121 The function also returns a new object of type D3D12MA::Allocation, created along
122 with usual `ID3D12Resource`. It represents allocated memory and can be queried
123 for size, offset, `ID3D12Resource`, and `ID3D12Heap` if needed.
124 
125 \code
126 D3D12_RESOURCE_DESC resourceDesc = {};
127 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
128 resourceDesc.Alignment = 0;
129 resourceDesc.Width = 1024;
130 resourceDesc.Height = 1024;
131 resourceDesc.DepthOrArraySize = 1;
132 resourceDesc.MipLevels = 1;
133 resourceDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
134 resourceDesc.SampleDesc.Count = 1;
135 resourceDesc.SampleDesc.Quality = 0;
136 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
137 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
138 
139 D3D12MA::ALLOCATION_DESC allocationDesc = {};
140 allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
141 
142 D3D12Resource* resource;
143 D3D12MA::Allocation* allocation;
144 HRESULT hr = allocator->CreateResource(
145     &allocationDesc,
146     &resourceDesc,
147     D3D12_RESOURCE_STATE_COPY_DEST,
148     NULL,
149     &allocation,
150     IID_PPV_ARGS(&resource));
151 \endcode
152 
153 You need to remember both resource and allocation objects and destroy them
154 separately when no longer needed.
155 
156 \code
157 allocation->Release();
158 resource->Release();
159 \endcode
160 
161 The advantage of using the allocator instead of creating committed resource, and
162 the main purpose of this library, is that it can decide to allocate bigger memory
163 heap internally using `ID3D12Device::CreateHeap` and place multiple resources in
164 it, at different offsets, using `ID3D12Device::CreatePlacedResource`. The library
165 manages its own collection of allocated memory blocks (heaps) and remembers which
166 parts of them are occupied and which parts are free to be used for new resources.
167 
168 It is important to remember that resources created as placed don't have their memory
169 initialized to zeros, but may contain garbage data, so they need to be fully initialized
170 before usage, e.g. using Clear (`ClearRenderTargetView`), Discard (`DiscardResource`),
171 or copy (`CopyResource`).
172 
173 The library also automatically handles resource heap tier.
174 When `D3D12_FEATURE_DATA_D3D12_OPTIONS::ResourceHeapTier` equals `D3D12_RESOURCE_HEAP_TIER_1`,
175 resources of 3 types: buffers, textures that are render targets or depth-stencil,
176 and other textures must be kept in separate heaps. When `D3D12_RESOURCE_HEAP_TIER_2`,
177 they can be kept together. By using this library, you don't need to handle this
178 manually.
179 
180 
181 \section quick_start_mapping_memory Mapping memory
182 
183 The process of getting regular CPU-side pointer to the memory of a resource in
184 Direct3D is called "mapping". There are rules and restrictions to this process,
185 as described in D3D12 documentation of [ID3D12Resource::Map method](https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12resource-map).
186 
187 Mapping happens on the level of particular resources, not entire memory heaps,
188 and so it is out of scope of this library. Just as the linked documentation says:
189 
190 - Returned pointer refers to data of particular subresource, not entire memory heap.
191 - You can map same resource multiple times. It is ref-counted internally.
192 - Mapping is thread-safe.
193 - Unmapping is not required before resource destruction.
194 - Unmapping may not be required before using written data - some heap types on
195   some platforms support resources persistently mapped.
196 
197 When using this library, you can map and use your resources normally without
198 considering whether they are created as committed resources or placed resources in one large heap.
199 
200 Example for buffer created and filled in `UPLOAD` heap type:
201 
202 \code
203 const UINT64 bufSize = 65536;
204 const float* bufData = (...);
205 
206 D3D12_RESOURCE_DESC resourceDesc = {};
207 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
208 resourceDesc.Alignment = 0;
209 resourceDesc.Width = bufSize;
210 resourceDesc.Height = 1;
211 resourceDesc.DepthOrArraySize = 1;
212 resourceDesc.MipLevels = 1;
213 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
214 resourceDesc.SampleDesc.Count = 1;
215 resourceDesc.SampleDesc.Quality = 0;
216 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
217 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
218 
219 D3D12MA::ALLOCATION_DESC allocationDesc = {};
220 allocationDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
221 
222 D3D12Resource* resource;
223 D3D12MA::Allocation* allocation;
224 HRESULT hr = allocator->CreateResource(
225     &allocationDesc,
226     &resourceDesc,
227     D3D12_RESOURCE_STATE_GENERIC_READ,
228     NULL,
229     &allocation,
230     IID_PPV_ARGS(&resource));
231 
232 void* mappedPtr;
233 hr = resource->Map(0, NULL, &mappedPtr);
234 
235 memcpy(mappedPtr, bufData, bufSize);
236 
237 resource->Unmap(0, NULL);
238 \endcode
239 
240 
241 \page resource_aliasing Resource aliasing (overlap)
242 
243 New explicit graphics APIs (Vulkan and Direct3D 12), thanks to manual memory
244 management, give an opportunity to alias (overlap) multiple resources in the
245 same region of memory - a feature not available in the old APIs (Direct3D 11, OpenGL).
246 It can be useful to save video memory, but it must be used with caution.
247 
248 For example, if you know the flow of your whole render frame in advance, you
249 are going to use some intermediate textures or buffers only during a small range of render passes,
250 and you know these ranges don't overlap in time, you can create these resources in
251 the same place in memory, even if they have completely different parameters (width, height, format etc.).
252 
253 ![Resource aliasing (overlap)](../gfx/Aliasing.png)
254 
255 Such scenario is possible using D3D12MA, but you need to create your resources
256 using special function D3D12MA::Allocator::CreateAliasingResource.
257 Before that, you need to allocate memory with parameters calculated using formula:
258 
259 - allocation size = max(size of each resource)
260 - allocation alignment = max(alignment of each resource)
261 
262 Following example shows two different textures created in the same place in memory,
263 allocated to fit largest of them.
264 
265 \code
266 D3D12_RESOURCE_DESC resDesc1 = {};
267 resDesc1.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
268 resDesc1.Alignment = 0;
269 resDesc1.Width = 1920;
270 resDesc1.Height = 1080;
271 resDesc1.DepthOrArraySize = 1;
272 resDesc1.MipLevels = 1;
273 resDesc1.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
274 resDesc1.SampleDesc.Count = 1;
275 resDesc1.SampleDesc.Quality = 0;
276 resDesc1.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
277 resDesc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
278 
279 D3D12_RESOURCE_DESC resDesc2 = {};
280 resDesc2.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
281 resDesc2.Alignment = 0;
282 resDesc2.Width = 1024;
283 resDesc2.Height = 1024;
284 resDesc2.DepthOrArraySize = 1;
285 resDesc2.MipLevels = 0;
286 resDesc2.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
287 resDesc2.SampleDesc.Count = 1;
288 resDesc2.SampleDesc.Quality = 0;
289 resDesc2.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
290 resDesc2.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
291 
292 const D3D12_RESOURCE_ALLOCATION_INFO allocInfo1 =
293     device->GetResourceAllocationInfo(0, 1, &resDesc1);
294 const D3D12_RESOURCE_ALLOCATION_INFO allocInfo2 =
295     device->GetResourceAllocationInfo(0, 1, &resDesc2);
296 
297 D3D12_RESOURCE_ALLOCATION_INFO finalAllocInfo = {};
298 finalAllocInfo.Alignment = std::max(allocInfo1.Alignment, allocInfo2.Alignment);
299 finalAllocInfo.SizeInBytes = std::max(allocInfo1.SizeInBytes, allocInfo2.SizeInBytes);
300 
301 D3D12MA::ALLOCATION_DESC allocDesc = {};
302 allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
303 allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
304 
305 D3D12MA::Allocation* alloc;
306 hr = allocator->AllocateMemory(&allocDesc, &finalAllocInfo, &alloc);
307 assert(alloc != NULL && alloc->GetHeap() != NULL);
308 
309 ID3D12Resource* res1;
310 hr = allocator->CreateAliasingResource(
311     alloc,
312     0, // AllocationLocalOffset
313     &resDesc1,
314     D3D12_RESOURCE_STATE_COMMON,
315     NULL, // pOptimizedClearValue
316     IID_PPV_ARGS(&res1));
317 
318 ID3D12Resource* res2;
319 hr = allocator->CreateAliasingResource(
320     alloc,
321     0, // AllocationLocalOffset
322     &resDesc2,
323     D3D12_RESOURCE_STATE_COMMON,
324     NULL, // pOptimizedClearValue
325     IID_PPV_ARGS(&res2));
326 
327 // You can use res1 and res2, but not at the same time!
328 
329 res2->Release();
330 res1->Release();
331 alloc->Release();
332 \endcode
333 
334 Remember that using resouces that alias in memory requires proper synchronization.
335 You need to issue a special barrier of type `D3D12_RESOURCE_BARRIER_TYPE_ALIASING`.
336 You also need to treat a resource after aliasing as uninitialized - containing garbage data.
337 For example, if you use `res1` and then want to use `res2`, you need to first initialize `res2`
338 using either Clear, Discard, or Copy to the entire resource.
339 
340 Additional considerations:
341 
342 - D3D12 also allows to interpret contents of memory between aliasing resources consistently in some cases,
343   which is called "data inheritance". For details, see
344   Microsoft documentation, chapter [Memory Aliasing and Data Inheritance](https://docs.microsoft.com/en-us/windows/win32/direct3d12/memory-aliasing-and-data-inheritance).
345 - You can create more complex layout where different textures and buffers are bound
346   at different offsets inside one large allocation. For example, one can imagine
347   a big texture used in some render passes, aliasing with a set of many small buffers
348   used in some further passes. To bind a resource at non-zero offset of an allocation,
349   call D3D12MA::Allocator::CreateAliasingResource with appropriate value of `AllocationLocalOffset` parameter.
350 - Resources of the three categories: buffers, textures with `RENDER_TARGET` or `DEPTH_STENCIL` flags, and all other textures,
351   can be placed in the same memory only when `allocator->GetD3D12Options().ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2`.
352   Otherwise they must be placed in different memory heap types, and thus aliasing them is not possible.
353 
354 
355 \page reserving_memory Reserving minimum amount of memory
356 
357 The library automatically allocates and frees memory heaps.
358 It also applies some hysteresis so that it doesn't allocate and free entire heap
359 when you repeatedly create and release a single resource.
360 However, if you want to make sure certain number of bytes is always allocated as heaps in a specific pool,
361 you can use functions designed for this purpose:
362 
363 - For default heaps use D3D12MA::Allocator::SetDefaultHeapMinBytes.
364 - For custom heaps use D3D12MA::Pool::SetMinBytes.
365 
366 Default is 0. You can change this parameter any time.
367 Setting it to higher value may cause new heaps to be allocated.
368 If this allocation fails, the function returns appropriate error code, but the parameter remains set to the new value.
369 Setting it to lower value may cause some empty heaps to be released.
370 
371 You can always call D3D12MA::Allocator::SetDefaultHeapMinBytes for 3 sets of heap flags separately:
372 `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`, `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`, `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
373 When ResourceHeapTier = 2, so that all types of resourced are kept together,
374 these 3 values as simply summed up to calculate minimum amount of bytes for default pool with certain heap type.
375 Alternatively, when ResourceHeapTier = 2, you can call this function with
376 `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0. This will set a single value for the default pool and
377 will override the sum of those three.
378 
379 Reservation of minimum number of bytes interacts correctly with
380 D3D12MA::POOL_DESC::MinBlockCount and D3D12MA::POOL_DESC::MaxBlockCount.
381 For example, free blocks (heaps) of a custom pool will be released only when
382 their number doesn't fall below `MinBlockCount` and their sum size doesn't fall below `MinBytes`.
383 
384 Some restrictions apply:
385 
386 - Setting `MinBytes` doesn't interact with memory budget. The allocator tries
387   to create additional heaps when necessary without checking if they will exceed the budget.
388 - Resources created as committed don't count into the number of bytes compared with `MinBytes` set.
389   Only placed resources are considered.
390 
391 
392 \page virtual_allocator Virtual allocator
393 
394 As an extra feature, the core allocation algorithm of the library is exposed through a simple and convenient API of "virtual allocator".
395 It doesn't allocate any real GPU memory. It just keeps track of used and free regions of a "virtual block".
396 You can use it to allocate your own memory or other objects, even completely unrelated to D3D12.
397 A common use case is sub-allocation of pieces of one large GPU buffer.
398 
399 \section virtual_allocator_creating_virtual_block Creating virtual block
400 
401 To use this functionality, there is no main "allocator" object.
402 You don't need to have D3D12MA::Allocator object created.
403 All 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:
404 
405 -# Fill in D3D12MA::ALLOCATOR_DESC structure.
406 -# Call D3D12MA::CreateVirtualBlock. Get new D3D12MA::VirtualBlock object.
407 
408 Example:
409 
410 \code
411 D3D12MA::VIRTUAL_BLOCK_DESC blockDesc = {};
412 blockDesc.Size = 1048576; // 1 MB
413 
414 D3D12MA::VirtualBlock *block;
415 HRESULT hr = CreateVirtualBlock(&blockDesc, &block);
416 \endcode
417 
418 \section virtual_allocator_making_virtual_allocations Making virtual allocations
419 
420 D3D12MA::VirtualBlock object contains internal data structure that keeps track of free and occupied regions
421 using the same code as the main D3D12 memory allocator.
422 However, there is no "virtual allocation" object.
423 When you request a new allocation, a `UINT64` number is returned.
424 It is an offset inside the block where the allocation has been placed, but it also uniquely identifies the allocation within this block.
425 
426 In order to make an allocation:
427 
428 -# Fill in D3D12MA::VIRTUAL_ALLOCATION_DESC structure.
429 -# Call D3D12MA::VirtualBlock::Allocate. Get new `UINT64 offset` that identifies the allocation.
430 
431 Example:
432 
433 \code
434 D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};
435 allocDesc.Size = 4096; // 4 KB
436 
437 UINT64 allocOffset;
438 hr = block->Allocate(&allocDesc, &allocOffset);
439 if(SUCCEEDED(hr))
440 {
441     // Use the 4 KB of your memory starting at allocOffset.
442 }
443 else
444 {
445     // Allocation failed - no space for it could be found. Handle this error!
446 }
447 \endcode
448 
449 \section virtual_allocator_deallocation Deallocation
450 
451 When no longer needed, an allocation can be freed by calling D3D12MA::VirtualBlock::FreeAllocation.
452 You can only pass to this function the exact offset that was previously returned by D3D12MA::VirtualBlock::Allocate
453 and not any other location within the memory.
454 
455 When whole block is no longer needed, the block object can be released by calling D3D12MA::VirtualBlock::Release.
456 All allocations must be freed before the block is destroyed, which is checked internally by an assert.
457 However, if you don't want to call `block->FreeAllocation` for each allocation, you can use D3D12MA::VirtualBlock::Clear to free them all at once -
458 a feature not available in normal D3D12 memory allocator. Example:
459 
460 \code
461 block->FreeAllocation(allocOffset);
462 block->Release();
463 \endcode
464 
465 \section virtual_allocator_allocation_parameters Allocation parameters
466 
467 You can attach a custom pointer to each allocation by using D3D12MA::VirtualBlock::SetAllocationUserData.
468 Its default value is `NULL`.
469 It 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 some
470 larger data structure containing more information. Example:
471 
472 \code
473 struct CustomAllocData
474 {
475     std::string m_AllocName;
476 };
477 CustomAllocData* allocData = new CustomAllocData();
478 allocData->m_AllocName = "My allocation 1";
479 block->SetAllocationUserData(allocOffset, allocData);
480 \endcode
481 
482 The pointer can later be fetched, along with allocation size, by passing the allocation offset to function
483 D3D12MA::VirtualBlock::GetAllocationInfo and inspecting returned structure D3D12MA::VIRTUAL_ALLOCATION_INFO.
484 If you allocated a new object to be used as the custom pointer, don't forget to delete that object before freeing the allocation!
485 Example:
486 
487 \code
488 VIRTUAL_ALLOCATION_INFO allocInfo;
489 block->GetAllocationInfo(allocOffset, &allocInfo);
490 delete (CustomAllocData*)allocInfo.pUserData;
491 
492 block->FreeAllocation(allocOffset);
493 \endcode
494 
495 \section virtual_allocator_alignment_and_units Alignment and units
496 
497 It feels natural to express sizes and offsets in bytes.
498 If an offset of an allocation needs to be aligned to a multiply of some number (e.g. 4 bytes), you can fill optional member
499 D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment to request it. Example:
500 
501 \code
502 D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};
503 allocDesc.Size = 4096; // 4 KB
504 allocDesc.Alignment = 4; // Returned offset must be a multiply of 4 B
505 
506 UINT64 allocOffset;
507 hr = block->Allocate(&allocDesc, &allocOffset);
508 \endcode
509 
510 Alignments of different allocations made from one block may vary.
511 However, if all alignments and sizes are always multiply of some size e.g. 4 B or `sizeof(MyDataStruct)`,
512 you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes.
513 It might be more convenient, but you need to make sure to use this new unit consistently in all the places:
514 
515 - D3D12MA::VIRTUAL_BLOCK_DESC::Size
516 - D3D12MA::VIRTUAL_ALLOCATION_DESC::Size and D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment
517 - Using offset returned by D3D12MA::VirtualBlock::Allocate
518 
519 \section virtual_allocator_statistics Statistics
520 
521 You can obtain statistics of a virtual block using D3D12MA::VirtualBlock::CalculateStats.
522 The function fills structure D3D12MA::StatInfo - same as used by the normal D3D12 memory allocator.
523 Example:
524 
525 \code
526 D3D12MA::StatInfo statInfo;
527 block->CalculateStats(&statInfo);
528 printf("My virtual block has %llu bytes used by %u virtual allocations\n",
529     statInfo.UsedBytes, statInfo.AllocationCount);
530 \endcode
531 
532 You can also request a full list of allocations and free regions as a string in JSON format by calling
533 D3D12MA::VirtualBlock::BuildStatsString.
534 Returned string must be later freed using D3D12MA::VirtualBlock::FreeStatsString.
535 The format of this string may differ from the one returned by the main D3D12 allocator, but it is similar.
536 
537 \section virtual_allocator_additional_considerations Additional considerations
538 
539 Note that the "virtual allocator" functionality is implemented on a level of individual memory blocks.
540 Keeping track of a whole collection of blocks, allocating new ones when out of free space,
541 deleting empty ones, and deciding which one to try first for a new allocation must be implemented by the user.
542 
543 
544 \page configuration Configuration
545 
546 Please check file `D3D12MemAlloc.cpp` lines between "Configuration Begin" and
547 "Configuration End" to find macros that you can define to change the behavior of
548 the library, primarily for debugging purposes.
549 
550 \section custom_memory_allocator Custom CPU memory allocator
551 
552 If you use custom allocator for CPU memory rather than default C++ operator `new`
553 and `delete` or `malloc` and `free` functions, you can make this library using
554 your allocator as well by filling structure D3D12MA::ALLOCATION_CALLBACKS and
555 passing it as optional member D3D12MA::ALLOCATOR_DESC::pAllocationCallbacks.
556 Functions pointed there will be used by the library to make any CPU-side
557 allocations. Example:
558 
559 \code
560 #include <malloc.h>
561 
562 void* CustomAllocate(size_t Size, size_t Alignment, void* pUserData)
563 {
564     void* memory = _aligned_malloc(Size, Alignment);
565     // Your extra bookkeeping here...
566     return memory;
567 }
568 
569 void CustomFree(void* pMemory, void* pUserData)
570 {
571     // Your extra bookkeeping here...
572     _aligned_free(pMemory);
573 }
574 
575 (...)
576 
577 D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};
578 allocationCallbacks.pAllocate = &CustomAllocate;
579 allocationCallbacks.pFree = &CustomFree;
580 
581 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
582 allocatorDesc.pDevice = device;
583 allocatorDesc.pAdapter = adapter;
584 allocatorDesc.pAllocationCallbacks = &allocationCallbacks;
585 
586 D3D12MA::Allocator* allocator;
587 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
588 \endcode
589 
590 
591 \page general_considerations General considerations
592 
593 \section general_considerations_thread_safety Thread safety
594 
595 - The library has no global state, so separate D3D12MA::Allocator objects can be used independently.
596   In typical applications there should be no need to create multiple such objects though - one per `ID3D12Device` is enough.
597 - All calls to methods of D3D12MA::Allocator class are safe to be made from multiple
598   threads simultaneously because they are synchronized internally when needed.
599 - When the allocator is created with D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED,
600   calls to methods of D3D12MA::Allocator class must be made from a single thread or synchronized by the user.
601   Using this flag may improve performance.
602 
603 \section general_considerations_future_plans Future plans
604 
605 Features planned for future releases:
606 
607 Near future: feature parity with [Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/), including:
608 
609 - Alternative allocation algorithms: linear allocator, buddy allocator
610 - Support for priorities using `ID3D12Device1::SetResidencyPriority`
611 
612 Later:
613 
614 - Memory defragmentation
615 - Support for multi-GPU (multi-adapter)
616 
617 \section general_considerations_features_not_supported Features not supported
618 
619 Features deliberately excluded from the scope of this library:
620 
621 - Descriptor allocation. Although also called "heaps", objects that represent
622   descriptors are separate part of the D3D12 API from buffers and textures.
623 - Support for `D3D12_HEAP_TYPE_CUSTOM`. Only the default heap types are supported:
624   `UPLOAD`, `DEFAULT`, `READBACK`.
625 - Support for reserved (tiled) resources. We don't recommend using them.
626 - Support for `ID3D12Device::Evict` and `MakeResident`. We don't recommend using them.
627 - Handling CPU memory allocation failures. When dynamically creating small C++
628   objects in CPU memory (not the GPU memory), allocation failures are not
629   handled gracefully, because that would complicate code significantly and
630   is usually not needed in desktop PC applications anyway.
631   Success of an allocation is just checked with an assert.
632 - Code free of any compiler warnings - especially those that would require complicating the code
633   just to please the compiler complaining about unused parameters, variables, or expressions being
634   constant in Relese configuration, e.g. because they are only used inside an assert.
635 - This is a C++ library.
636   Bindings or ports to any other programming languages are welcomed as external projects and
637   are not going to be included into this repository.
638 */
639 
640 // Define this macro to 0 to disable usage of DXGI 1.4 (needed for IDXGIAdapter3 and query for memory budget).
641 #ifndef D3D12MA_DXGI_1_4
642     #define D3D12MA_DXGI_1_4 1
643 #endif
644 
645 // If using this library on a platform different than Windows PC, you should
646 // include D3D12-compatible header before this library on your own and define this macro.
647 #ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
648     #include <d3d12.h>
649     #include <dxgi.h>
650 #endif
651 
652 /*
653 When defined to value other than 0, the library will try to use
654 D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT or D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT
655 for created textures when possible, which can save memory because some small textures
656 may get their alignment 4K and their size a multiply of 4K instead of 64K.
657 
658 #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 0
659     Disables small texture alignment.
660 #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1
661     Enables conservative algorithm that will use small alignment only for some textures
662     that are surely known to support it.
663 #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 2
664     Enables query for small alignment to D3D12 (based on Microsoft sample) which will
665     enable small alignment for more textures, but will also generate D3D Debug Layer
666     error #721 on call to ID3D12Device::GetResourceAllocationInfo, which you should just
667     ignore.
668 */
669 #ifndef D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
670     #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1
671 #endif
672 
673 /// \cond INTERNAL
674 
675 #define D3D12MA_CLASS_NO_COPY(className) \
676     private: \
677         className(const className&) = delete; \
678         className(className&&) = delete; \
679         className& operator=(const className&) = delete; \
680         className& operator=(className&&) = delete;
681 
682 // To be used with MAKE_HRESULT to define custom error codes.
683 #define FACILITY_D3D12MA 3542
684 
685 /// \endcond
686 
687 namespace D3D12MA
688 {
689 
690 /// \cond INTERNAL
691 class AllocatorPimpl;
692 class PoolPimpl;
693 class NormalBlock;
694 class BlockVector;
695 class JsonWriter;
696 class VirtualBlockPimpl;
697 /// \endcond
698 
699 class Pool;
700 class Allocator;
701 struct StatInfo;
702 
703 /// Pointer to custom callback function that allocates CPU memory.
704 typedef void* (*ALLOCATE_FUNC_PTR)(size_t Size, size_t Alignment, void* pUserData);
705 /**
706 \brief Pointer to custom callback function that deallocates CPU memory.
707 
708 `pMemory = null` should be accepted and ignored.
709 */
710 typedef void (*FREE_FUNC_PTR)(void* pMemory, void* pUserData);
711 
712 /// Custom callbacks to CPU memory allocation functions.
713 struct ALLOCATION_CALLBACKS
714 {
715     /// %Allocation function.
716     ALLOCATE_FUNC_PTR pAllocate;
717     /// Dellocation function.
718     FREE_FUNC_PTR pFree;
719     /// Custom data that will be passed to allocation and deallocation functions as `pUserData` parameter.
720     void* pUserData;
721 };
722 
723 /// \brief Bit flags to be used with ALLOCATION_DESC::Flags.
724 typedef enum ALLOCATION_FLAGS
725 {
726     /// Zero
727     ALLOCATION_FLAG_NONE = 0,
728 
729     /**
730     Set this flag if the allocation should have its own dedicated memory allocation (committed resource with implicit heap).
731 
732     Use it for special, big resources, like fullscreen textures used as render targets.
733     */
734     ALLOCATION_FLAG_COMMITTED = 0x1,
735 
736     /**
737     Set this flag to only try to allocate from existing memory heaps and never create new such heap.
738 
739     If new allocation cannot be placed in any of the existing heaps, allocation
740     fails with `E_OUTOFMEMORY` error.
741 
742     You should not use D3D12MA::ALLOCATION_FLAG_COMMITTED and
743     D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.
744     */
745     ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2,
746 
747     /** Create allocation only if additional memory required for it, if any, won't exceed
748     memory budget. Otherwise return `E_OUTOFMEMORY`.
749     */
750     ALLOCATION_FLAG_WITHIN_BUDGET = 0x4,
751 } ALLOCATION_FLAGS;
752 
753 /// \brief Parameters of created D3D12MA::Allocation object. To be used with Allocator::CreateResource.
754 struct ALLOCATION_DESC
755 {
756     /// Flags.
757     ALLOCATION_FLAGS Flags;
758     /** \brief The type of memory heap where the new allocation should be placed.
759 
760     It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
761 
762     When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
763     */
764     D3D12_HEAP_TYPE HeapType;
765     /** \brief Additional heap flags to be used when allocating memory.
766 
767     In most cases it can be 0.
768 
769     - If you use D3D12MA::Allocator::CreateResource(), you don't need to care.
770       Necessary flag `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`, `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
771       or `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES` is added automatically.
772     - If you use D3D12MA::Allocator::AllocateMemory(), you should specify one of those `ALLOW_ONLY` flags.
773       Except when you validate that D3D12MA::Allocator::GetD3D12Options()`.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1` -
774       then you can leave it 0.
775     - You can specify additional flags if needed. Then the memory will always be allocated as
776       separate block using `D3D12Device::CreateCommittedResource` or `CreateHeap`, not as part of an existing larget block.
777 
778     When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
779     */
780     D3D12_HEAP_FLAGS ExtraHeapFlags;
781     /** \brief Custom pool to place the new resource in. Optional.
782 
783     When not NULL, the resource will be created inside specified custom pool.
784     It will then never be created as committed.
785     */
786     Pool* CustomPool;
787 };
788 
789 /** \brief Represents single memory allocation.
790 
791 It may be either implicit memory heap dedicated to a single resource or a
792 specific region of a bigger heap plus unique offset.
793 
794 To create such object, fill structure D3D12MA::ALLOCATION_DESC and call function
795 Allocator::CreateResource.
796 
797 The object remembers size and some other information.
798 To retrieve this information, use methods of this class.
799 
800 The object also remembers `ID3D12Resource` and "owns" a reference to it,
801 so it calls `Release()` on the resource when destroyed.
802 */
803 class Allocation
804 {
805 public:
806     /** \brief Deletes this object.
807 
808     This function must be used instead of destructor, which is private.
809     There is no reference counting involved.
810     */
811     void Release();
812 
813     /** \brief Returns offset in bytes from the start of memory heap.
814 
815     If the Allocation represents committed resource with implicit heap, returns 0.
816     */
817     UINT64 GetOffset() const;
818 
819     /** \brief Returns size in bytes of the resource.
820 
821     Works also with committed resources.
822     */
GetSize()823     UINT64 GetSize() const { return m_Size; }
824 
825     /** \brief Returns D3D12 resource associated with this object.
826 
827     Calling this method doesn't increment resource's reference counter.
828     */
GetResource()829     ID3D12Resource* GetResource() const { return m_Resource; }
830 
831     /** \brief Returns memory heap that the resource is created in.
832 
833     If the Allocation represents committed resource with implicit heap, returns NULL.
834     */
835     ID3D12Heap* GetHeap() const;
836 
837     /** \brief Associates a name with the allocation object. This name is for use in debug diagnostics and tools.
838 
839     Internal copy of the string is made, so the memory pointed by the argument can be
840     changed of freed immediately after this call.
841 
842     `Name` can be null.
843     */
844     void SetName(LPCWSTR Name);
845 
846     /** \brief Returns the name associated with the allocation object.
847 
848     Returned string points to an internal copy.
849 
850     If no name was associated with the allocation, returns null.
851     */
GetName()852     LPCWSTR GetName() const { return m_Name; }
853 
854     /** \brief Returns `TRUE` if the memory of the allocation was filled with zeros when the allocation was created.
855 
856     Returns `TRUE` only if the allocator is sure that the entire memory where the
857     allocation was created was filled with zeros at the moment the allocation was made.
858 
859     Returns `FALSE` if the memory could potentially contain garbage data.
860     If it's a render-target or depth-stencil texture, it then needs proper
861     initialization with `ClearRenderTargetView`, `ClearDepthStencilView`, `DiscardResource`,
862     or a copy operation, as described on page:
863     [ID3D12Device::CreatePlacedResource method - Notes on the required resource initialization](https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource#notes-on-the-required-resource-initialization).
864     Please note that rendering a fullscreen triangle or quad to the texture as
865     a render target is not a proper way of initialization!
866 
867     See also articles:
868     ["Coming to DirectX 12: More control over memory allocation"](https://devblogs.microsoft.com/directx/coming-to-directx-12-more-control-over-memory-allocation/),
869     ["Initializing DX12 Textures After Allocation and Aliasing"](https://asawicki.info/news_1724_initializing_dx12_textures_after_allocation_and_aliasing).
870     */
WasZeroInitialized()871     BOOL WasZeroInitialized() const { return m_PackedData.WasZeroInitialized(); }
872 
873 private:
874     friend class AllocatorPimpl;
875     friend class BlockVector;
876     friend class JsonWriter;
877     template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
878     template<typename T> friend class PoolAllocator;
879 
880     enum Type
881     {
882         TYPE_COMMITTED,
883         TYPE_PLACED,
884         TYPE_HEAP,
885         TYPE_COUNT
886     };
887 
888     AllocatorPimpl* m_Allocator;
889     UINT64 m_Size;
890     ID3D12Resource* m_Resource;
891     UINT m_CreationFrameIndex;
892     wchar_t* m_Name;
893 
894     union
895     {
896         struct
897         {
898             D3D12_HEAP_TYPE heapType;
899         } m_Committed;
900 
901         struct
902         {
903             UINT64 offset;
904             NormalBlock* block;
905         } m_Placed;
906 
907         struct
908         {
909             D3D12_HEAP_TYPE heapType;
910             ID3D12Heap* heap;
911         } m_Heap;
912     };
913 
914     struct PackedData
915     {
916     public:
PackedDataPackedData917         PackedData() :
918             m_Type(0), m_ResourceDimension(0), m_ResourceFlags(0), m_TextureLayout(0), m_WasZeroInitialized(0) { }
919 
GetTypePackedData920         Type GetType() const { return (Type)m_Type; }
GetResourceDimensionPackedData921         D3D12_RESOURCE_DIMENSION GetResourceDimension() const { return (D3D12_RESOURCE_DIMENSION)m_ResourceDimension; }
GetResourceFlagsPackedData922         D3D12_RESOURCE_FLAGS GetResourceFlags() const { return (D3D12_RESOURCE_FLAGS)m_ResourceFlags; }
GetTextureLayoutPackedData923         D3D12_TEXTURE_LAYOUT GetTextureLayout() const { return (D3D12_TEXTURE_LAYOUT)m_TextureLayout; }
WasZeroInitializedPackedData924         BOOL WasZeroInitialized() const { return (BOOL)m_WasZeroInitialized; }
925 
926         void SetType(Type type);
927         void SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension);
928         void SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags);
929         void SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout);
SetWasZeroInitializedPackedData930         void SetWasZeroInitialized(BOOL wasZeroInitialized) { m_WasZeroInitialized = wasZeroInitialized ? 1 : 0; }
931 
932     private:
933         UINT m_Type : 2;               // enum Type
934         UINT m_ResourceDimension : 3;  // enum D3D12_RESOURCE_DIMENSION
935         UINT m_ResourceFlags : 24;     // flags D3D12_RESOURCE_FLAGS
936         UINT m_TextureLayout : 9;      // enum D3D12_TEXTURE_LAYOUT
937         UINT m_WasZeroInitialized : 1; // BOOL
938     } m_PackedData;
939 
940     Allocation(AllocatorPimpl* allocator, UINT64 size, BOOL wasZeroInitialized);
941     ~Allocation();
942     void InitCommitted(D3D12_HEAP_TYPE heapType);
943     void InitPlaced(UINT64 offset, UINT64 alignment, NormalBlock* block);
944     void InitHeap(D3D12_HEAP_TYPE heapType, ID3D12Heap* heap);
945     void SetResource(ID3D12Resource* resource, const D3D12_RESOURCE_DESC* pResourceDesc);
946     void FreeName();
947 
948     D3D12MA_CLASS_NO_COPY(Allocation)
949 };
950 
951 /// \brief Parameters of created D3D12MA::Pool object. To be used with D3D12MA::Allocator::CreatePool.
952 struct POOL_DESC
953 {
954     /** \brief The type of memory heap where allocations of this pool should be placed.
955 
956     It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
957     */
958     D3D12_HEAP_TYPE HeapType;
959     /** \brief Heap flags to be used when allocating heaps of this pool.
960 
961     It should contain one of these values, depending on type of resources you are going to create in this heap:
962     `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
963     `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
964     `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
965     Except if ResourceHeapTier = 2, then it may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
966 
967     You can specify additional flags if needed.
968     */
969     D3D12_HEAP_FLAGS HeapFlags;
970     /** \brief Size of a single heap (memory block) to be allocated as part of this pool, in bytes. Optional.
971 
972     Specify nonzero to set explicit, constant size of memory blocks used by this pool.
973     Leave 0 to use default and let the library manage block sizes automatically.
974     Then sizes of particular blocks may vary.
975     */
976     UINT64 BlockSize;
977     /** \brief Minimum number of heaps (memory blocks) to be always allocated in this pool, even if they stay empty. Optional.
978 
979     Set to 0 to have no preallocated blocks and allow the pool be completely empty.
980     */
981     UINT MinBlockCount;
982     /** \brief Maximum number of heaps (memory blocks) that can be allocated in this pool. Optional.
983 
984     Set to 0 to use default, which is `UINT64_MAX`, which means no limit.
985 
986     Set to same value as D3D12MA::POOL_DESC::MinBlockCount to have fixed amount of memory allocated
987     throughout whole lifetime of this pool.
988     */
989     UINT MaxBlockCount;
990 };
991 
992 /** \brief Custom memory pool
993 
994 Represents a separate set of heaps (memory blocks) that can be used to create
995 D3D12MA::Allocation-s and resources in it. Usually there is no need to create custom
996 pools - creating resources in default pool is sufficient.
997 
998 To create custom pool, fill D3D12MA::POOL_DESC and call D3D12MA::Allocator::CreatePool.
999 */
1000 class Pool
1001 {
1002 public:
1003     /** \brief Deletes pool object, frees D3D12 heaps (memory blocks) managed by it. Allocations and resources must already be released!
1004 
1005     It doesn't delete allocations and resources created in this pool. They must be all
1006     released before calling this function!
1007     */
1008     void Release();
1009 
1010     /** \brief Returns copy of parameters of the pool.
1011 
1012     These are the same parameters as passed to D3D12MA::Allocator::CreatePool.
1013     */
1014     POOL_DESC GetDesc() const;
1015 
1016     /** \brief Sets the minimum number of bytes that should always be allocated (reserved) in this pool.
1017 
1018     See also: \subpage reserving_memory.
1019     */
1020     HRESULT SetMinBytes(UINT64 minBytes);
1021 
1022     /** \brief Retrieves statistics from the current state of this pool.
1023     */
1024     void CalculateStats(StatInfo* pStats);
1025 
1026     /** \brief Associates a name with the pool. This name is for use in debug diagnostics and tools.
1027 
1028     Internal copy of the string is made, so the memory pointed by the argument can be
1029     changed of freed immediately after this call.
1030 
1031     `Name` can be NULL.
1032     */
1033     void SetName(LPCWSTR Name);
1034 
1035     /** \brief Returns the name associated with the pool object.
1036 
1037     Returned string points to an internal copy.
1038 
1039     If no name was associated with the allocation, returns NULL.
1040     */
1041     LPCWSTR GetName() const;
1042 
1043 private:
1044     friend class Allocator;
1045     friend class AllocatorPimpl;
1046     template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
1047 
1048     PoolPimpl* m_Pimpl;
1049 
1050     Pool(Allocator* allocator, const POOL_DESC &desc);
1051     ~Pool();
1052 
1053     D3D12MA_CLASS_NO_COPY(Pool)
1054 };
1055 
1056 /// \brief Bit flags to be used with ALLOCATOR_DESC::Flags.
1057 typedef enum ALLOCATOR_FLAGS
1058 {
1059     /// Zero
1060     ALLOCATOR_FLAG_NONE = 0,
1061 
1062     /**
1063     Allocator and all objects created from it will not be synchronized internally,
1064     so you must guarantee they are used from only one thread at a time or
1065     synchronized by you.
1066 
1067     Using this flag may increase performance because internal mutexes are not used.
1068     */
1069     ALLOCATOR_FLAG_SINGLETHREADED = 0x1,
1070 
1071     /**
1072     Every allocation will have its own memory block.
1073     To be used for debugging purposes.
1074    */
1075     ALLOCATOR_FLAG_ALWAYS_COMMITTED = 0x2,
1076 } ALLOCATOR_FLAGS;
1077 
1078 /// \brief Parameters of created Allocator object. To be used with CreateAllocator().
1079 struct ALLOCATOR_DESC
1080 {
1081     /// Flags.
1082     ALLOCATOR_FLAGS Flags;
1083 
1084     /** Direct3D device object that the allocator should be attached to.
1085 
1086     Allocator is doing `AddRef`/`Release` on this object.
1087     */
1088     ID3D12Device* pDevice;
1089 
1090     /** \brief Preferred size of a single `ID3D12Heap` block to be allocated.
1091 
1092     Set to 0 to use default, which is currently 256 MiB.
1093     */
1094     UINT64 PreferredBlockSize;
1095 
1096     /** \brief Custom CPU memory allocation callbacks. Optional.
1097 
1098     Optional, can be null. When specified, will be used for all CPU-side memory allocations.
1099     */
1100     const ALLOCATION_CALLBACKS* pAllocationCallbacks;
1101 
1102     /** DXGI Adapter object that you use for D3D12 and this allocator.
1103 
1104     Allocator is doing `AddRef`/`Release` on this object.
1105     */
1106     IDXGIAdapter* pAdapter;
1107 };
1108 
1109 /**
1110 \brief Number of D3D12 memory heap types supported.
1111 */
1112 const UINT HEAP_TYPE_COUNT = 3;
1113 
1114 /**
1115 \brief Calculated statistics of memory usage in entire allocator.
1116 */
1117 struct StatInfo
1118 {
1119     /// Number of memory blocks (heaps) allocated.
1120     UINT BlockCount;
1121     /// Number of D3D12MA::Allocation objects allocated.
1122     UINT AllocationCount;
1123     /// Number of free ranges of memory between allocations.
1124     UINT UnusedRangeCount;
1125     /// Total number of bytes occupied by all allocations.
1126     UINT64 UsedBytes;
1127     /// Total number of bytes occupied by unused ranges.
1128     UINT64 UnusedBytes;
1129     UINT64 AllocationSizeMin;
1130     UINT64 AllocationSizeAvg;
1131     UINT64 AllocationSizeMax;
1132     UINT64 UnusedRangeSizeMin;
1133     UINT64 UnusedRangeSizeAvg;
1134     UINT64 UnusedRangeSizeMax;
1135 };
1136 
1137 /**
1138 \brief General statistics from the current state of the allocator.
1139 */
1140 struct Stats
1141 {
1142     /// Total statistics from all heap types.
1143     StatInfo Total;
1144     /**
1145     One StatInfo for each type of heap located at the following indices:
1146     0 - DEFAULT, 1 - UPLOAD, 2 - READBACK.
1147     */
1148     StatInfo HeapType[HEAP_TYPE_COUNT];
1149 };
1150 
1151 /** \brief Statistics of current memory usage and available budget, in bytes, for GPU or CPU memory.
1152 */
1153 struct Budget
1154 {
1155     /** \brief Sum size of all memory blocks allocated from particular heap type, in bytes.
1156     */
1157     UINT64 BlockBytes;
1158 
1159     /** \brief Sum size of all allocations created in particular heap type, in bytes.
1160 
1161     Always less or equal than `BlockBytes`.
1162     Difference `BlockBytes - AllocationBytes` is the amount of memory allocated but unused -
1163     available for new allocations or wasted due to fragmentation.
1164     */
1165     UINT64 AllocationBytes;
1166 
1167     /** \brief Estimated current memory usage of the program, in bytes.
1168 
1169     Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if enabled.
1170 
1171     It might be different than `BlockBytes` (usually higher) due to additional implicit objects
1172     also occupying the memory, like swapchain, pipeline state objects, descriptor heaps, command lists, or
1173     memory blocks allocated outside of this library, if any.
1174     */
1175     UINT64 UsageBytes;
1176 
1177     /** \brief Estimated amount of memory available to the program, in bytes.
1178 
1179     Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if enabled.
1180 
1181     It might be different (most probably smaller) than memory sizes reported in `DXGI_ADAPTER_DESC` due to factors
1182     external to the program, like other programs also consuming system resources.
1183     Difference `BudgetBytes - UsageBytes` is the amount of additional memory that can probably
1184     be allocated without problems. Exceeding the budget may result in various problems.
1185     */
1186     UINT64 BudgetBytes;
1187 };
1188 
1189 /**
1190 \brief Represents main object of this library initialized for particular `ID3D12Device`.
1191 
1192 Fill structure D3D12MA::ALLOCATOR_DESC and call function CreateAllocator() to create it.
1193 Call method Allocator::Release to destroy it.
1194 
1195 It is recommended to create just one object of this type per `ID3D12Device` object,
1196 right after Direct3D 12 is initialized and keep it alive until before Direct3D device is destroyed.
1197 */
1198 class Allocator
1199 {
1200 public:
1201     /** \brief Deletes this object.
1202 
1203     This function must be used instead of destructor, which is private.
1204     There is no reference counting involved.
1205     */
1206     void Release();
1207 
1208     /// Returns cached options retrieved from D3D12 device.
1209     const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const;
1210 
1211     /** \brief Allocates memory and creates a D3D12 resource (buffer or texture). This is the main allocation function.
1212 
1213     The function is similar to `ID3D12Device::CreateCommittedResource`, but it may
1214     really call `ID3D12Device::CreatePlacedResource` to assign part of a larger,
1215     existing memory heap to the new resource, which is the main purpose of this
1216     whole library.
1217 
1218     If `ppvResource` is null, you receive only `ppAllocation` object from this function.
1219     It holds pointer to `ID3D12Resource` that can be queried using function D3D12::Allocation::GetResource().
1220     Reference count of the resource object is 1.
1221     It is automatically destroyed when you destroy the allocation object.
1222 
1223     If 'ppvResource` is not null, you receive pointer to the resource next to allocation object.
1224     Reference count of the resource object is then increased by calling `QueryInterface`, so you need to manually `Release` it
1225     along with the allocation.
1226 
1227     \param pAllocDesc   Parameters of the allocation.
1228     \param pResourceDesc   Description of created resource.
1229     \param InitialResourceState   Initial resource state.
1230     \param pOptimizedClearValue   Optional. Either null or optimized clear value.
1231     \param[out] ppAllocation   Filled with pointer to new allocation object created.
1232     \param riidResource   IID of a resource to be returned via `ppvResource`.
1233     \param[out] ppvResource   Optional. If not null, filled with pointer to new resouce created.
1234     */
1235     HRESULT CreateResource(
1236         const ALLOCATION_DESC* pAllocDesc,
1237         const D3D12_RESOURCE_DESC* pResourceDesc,
1238         D3D12_RESOURCE_STATES InitialResourceState,
1239         const D3D12_CLEAR_VALUE *pOptimizedClearValue,
1240         Allocation** ppAllocation,
1241         REFIID riidResource,
1242         void** ppvResource);
1243 
1244     /** \brief Allocates memory without creating any resource placed in it.
1245 
1246     This function is similar to `ID3D12Device::CreateHeap`, but it may really assign
1247     part of a larger, existing heap to the allocation.
1248 
1249     `pAllocDesc->heapFlags` should contain one of these values, depending on type of resources you are going to create in this memory:
1250     `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
1251     `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
1252     `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
1253     Except if you validate that ResourceHeapTier = 2 - then `heapFlags`
1254     may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
1255     Additional flags in `heapFlags` are allowed as well.
1256 
1257     `pAllocInfo->SizeInBytes` must be multiply of 64KB.
1258     `pAllocInfo->Alignment` must be one of the legal values as described in documentation of `D3D12_HEAP_DESC`.
1259 
1260     If you use D3D12MA::ALLOCATION_FLAG_COMMITTED you will get a separate memory block -
1261     a heap that always has offset 0.
1262     */
1263     HRESULT AllocateMemory(
1264         const ALLOCATION_DESC* pAllocDesc,
1265         const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
1266         Allocation** ppAllocation);
1267 
1268     /** \brief Creates a new resource in place of an existing allocation. This is useful for memory aliasing.
1269 
1270     \param pAllocation Existing allocation indicating the memory where the new resource should be created.
1271         It can be created using D3D12MA::Allocator::CreateResource and already have a resource bound to it,
1272         or can be a raw memory allocated with D3D12MA::Allocator::AllocateMemory.
1273         It must not be created as committed so that `ID3D12Heap` is available and not implicit.
1274     \param AllocationLocalOffset Additional offset in bytes to be applied when allocating the resource.
1275         Local from the start of `pAllocation`, not the beginning of the whole `ID3D12Heap`!
1276         If the new resource should start from the beginning of the `pAllocation` it should be 0.
1277     \param pResourceDesc Description of the new resource to be created.
1278     \param InitialResourceState
1279     \param pOptimizedClearValue
1280     \param riidResource
1281     \param[out] ppvResource Returns pointer to the new resource.
1282         The resource is not bound with `pAllocation`.
1283         This pointer must not be null - you must get the resource pointer and `Release` it when no longer needed.
1284 
1285     Memory requirements of the new resource are checked for validation.
1286     If its size exceeds the end of `pAllocation` or required alignment is not fulfilled
1287     considering `pAllocation->GetOffset() + AllocationLocalOffset`, the function
1288     returns `E_INVALIDARG`.
1289     */
1290     HRESULT CreateAliasingResource(
1291         Allocation* pAllocation,
1292         UINT64 AllocationLocalOffset,
1293         const D3D12_RESOURCE_DESC* pResourceDesc,
1294         D3D12_RESOURCE_STATES InitialResourceState,
1295         const D3D12_CLEAR_VALUE *pOptimizedClearValue,
1296         REFIID riidResource,
1297         void** ppvResource);
1298 
1299     /** \brief Creates custom pool.
1300     */
1301     HRESULT CreatePool(
1302         const POOL_DESC* pPoolDesc,
1303         Pool** ppPool);
1304 
1305     /** \brief Sets the minimum number of bytes that should always be allocated (reserved) in a specific default pool.
1306 
1307     \param heapType Must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
1308     \param heapFlags Must be one of: `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`, `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
1309         `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`. If ResourceHeapTier = 2, it can also be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES`.
1310     \param minBytes Minimum number of bytes to keep allocated.
1311 
1312     See also: \subpage reserving_memory.
1313     */
1314     HRESULT SetDefaultHeapMinBytes(
1315         D3D12_HEAP_TYPE heapType,
1316         D3D12_HEAP_FLAGS heapFlags,
1317         UINT64 minBytes);
1318 
1319     /** \brief Sets the index of the current frame.
1320 
1321     This function is used to set the frame index in the allocator when a new game frame begins.
1322     */
1323     void SetCurrentFrameIndex(UINT frameIndex);
1324 
1325     /** \brief Retrieves statistics from the current state of the allocator.
1326     */
1327     void CalculateStats(Stats* pStats);
1328 
1329     /** \brief Retrieves information about current memory budget.
1330 
1331     \param[out] pGpuBudget Optional, can be null.
1332     \param[out] pCpuBudget Optional, can be null.
1333 
1334     This function is called "get" not "calculate" because it is very fast, suitable to be called
1335     every frame or every allocation. For more detailed statistics use CalculateStats().
1336 
1337     Note that when using allocator from multiple threads, returned information may immediately
1338     become outdated.
1339     */
1340     void GetBudget(Budget* pGpuBudget, Budget* pCpuBudget);
1341 
1342     /// Builds and returns statistics as a string in JSON format.
1343     /** @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
1344     @param DetailedMap `TRUE` to include full list of allocations (can make the string quite long), `FALSE` to only return statistics.
1345     */
1346     void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const;
1347 
1348     /// Frees memory of a string returned from Allocator::BuildStatsString.
1349     void FreeStatsString(WCHAR* pStatsString) const;
1350 
1351 private:
1352     friend HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);
1353     template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
1354     friend class Pool;
1355 
1356     Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
1357     ~Allocator();
1358 
1359     AllocatorPimpl* m_Pimpl;
1360 
1361     D3D12MA_CLASS_NO_COPY(Allocator)
1362 };
1363 
1364 /// Parameters of created D3D12MA::VirtualBlock object to be passed to CreateVirtualBlock().
1365 struct VIRTUAL_BLOCK_DESC
1366 {
1367     /** \brief Total size of the block.
1368 
1369     Sizes can be expressed in bytes or any units you want as long as you are consistent in using them.
1370     For example, if you allocate from some array of structures, 1 can mean single instance of entire structure.
1371     */
1372     UINT64 Size;
1373     /** \brief Custom CPU memory allocation callbacks. Optional.
1374 
1375     Optional, can be null. When specified, will be used for all CPU-side memory allocations.
1376     */
1377     const ALLOCATION_CALLBACKS* pAllocationCallbacks;
1378 };
1379 
1380 /// Parameters of created virtual allocation to be passed to VirtualBlock::Allocate().
1381 struct VIRTUAL_ALLOCATION_DESC
1382 {
1383     /** \brief Size of the allocation.
1384 
1385     Cannot be zero.
1386     */
1387     UINT64 Size;
1388     /** \brief Required alignment of the allocation.
1389 
1390     Must 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.
1391     */
1392     UINT64 Alignment;
1393     /** \brief Custom pointer to be associated with the allocation.
1394 
1395     It can be fetched or changed later.
1396     */
1397     void* pUserData;
1398 };
1399 
1400 /// Parameters of an existing virtual allocation, returned by VirtualBlock::GetAllocationInfo().
1401 struct VIRTUAL_ALLOCATION_INFO
1402 {
1403     /** \brief Size of the allocation.
1404 
1405     Same value as passed in VIRTUAL_ALLOCATION_DESC::Size.
1406     */
1407     UINT64 size;
1408     /** \brief Custom pointer associated with the allocation.
1409 
1410     Same value as passed in VIRTUAL_ALLOCATION_DESC::pUserData or VirtualBlock::SetAllocationUserData().
1411     */
1412     void* pUserData;
1413 };
1414 
1415 /** \brief Represents pure allocation algorithm and a data structure with allocations in some memory block, without actually allocating any GPU memory.
1416 
1417 This class allows to use the core algorithm of the library custom allocations e.g. CPU memory or
1418 sub-allocation regions inside a single GPU buffer.
1419 
1420 To create this object, fill in D3D12MA::VIRTUAL_BLOCK_DESC and call CreateVirtualBlock().
1421 To destroy it, call its method VirtualBlock::Release().
1422 */
1423 class VirtualBlock
1424 {
1425 public:
1426     /** \brief Destroys this object and frees it from memory.
1427 
1428     You need to free all the allocations within this block or call Clear() before destroying it.
1429     */
1430     void Release();
1431 
1432     /** \brief Returns true if the block is empty - contains 0 allocations.
1433     */
1434     BOOL IsEmpty() const;
1435     /** \brief Returns information about an allocation at given offset - its size and custom pointer.
1436     */
1437     void GetAllocationInfo(UINT64 offset, VIRTUAL_ALLOCATION_INFO* pInfo) const;
1438 
1439     /** \brief Creates new allocation.
1440     \param pDesc
1441     \param[out] pOffset Offset of the new allocation, which can also be treated as an unique identifier of the allocation within this block. `UINT64_MAX` if allocation failed.
1442     \return `S_OK` if allocation succeeded, `E_OUTOFMEMORY` if it failed.
1443     */
1444     HRESULT Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, UINT64* pOffset);
1445     /** \brief Frees the allocation at given offset.
1446     */
1447     void FreeAllocation(UINT64 offset);
1448     /** \brief Frees all the allocations.
1449     */
1450     void Clear();
1451     /** \brief Changes custom pointer for an allocation at given offset to a new value.
1452     */
1453     void SetAllocationUserData(UINT64 offset, void* pUserData);
1454 
1455     /** \brief Retrieves statistics from the current state of the block.
1456     */
1457     void CalculateStats(StatInfo* pInfo) const;
1458 
1459     /** \brief Builds and returns statistics as a string in JSON format, including the list of allocations with their parameters.
1460     @param[out] ppStatsString Must be freed using VirtualBlock::FreeStatsString.
1461     */
1462     void BuildStatsString(WCHAR** ppStatsString) const;
1463 
1464     /** \brief Frees memory of a string returned from VirtualBlock::BuildStatsString.
1465     */
1466     void FreeStatsString(WCHAR* pStatsString) const;
1467 
1468 private:
1469     friend HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC*, VirtualBlock**);
1470     template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
1471 
1472     VirtualBlockPimpl* m_Pimpl;
1473 
1474     VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
1475     ~VirtualBlock();
1476 
1477     D3D12MA_CLASS_NO_COPY(VirtualBlock)
1478 };
1479 
1480 /** \brief Creates new main D3D12MA::Allocator object and returns it through `ppAllocator`.
1481 
1482 You normally only need to call it once and keep a single Allocator object for your `ID3D12Device`.
1483 */
1484 HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator);
1485 
1486 /** \brief Creates new D3D12MA::VirtualBlock object and returns it through `ppVirtualBlock`.
1487 
1488 Note you don't need to create D3D12MA::Allocator to use virtual blocks.
1489 */
1490 HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock);
1491 
1492 } // namespace D3D12MA
1493 
1494 /// \cond INTERNAL
1495 DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATION_FLAGS);
1496 DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATOR_FLAGS);
1497 /// \endcond
1498