Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/d3d12ma/D3D12MemAlloc.h
22071 views
1
//
2
// Copyright (c) 2019-2025 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.1.0-development</b> (2024-07-05)
28
29
Copyright (c) 2019-2025 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
- \subpage quick_start
37
- [Project setup](@ref quick_start_project_setup)
38
- [Creating resources](@ref quick_start_creating_resources)
39
- [Resource reference counting](@ref quick_start_resource_reference_counting)
40
- [Mapping memory](@ref quick_start_mapping_memory)
41
- [Helper structures](@ref quick_start_helper_structures)
42
- \subpage custom_pools
43
- \subpage optimal_allocation
44
- [Avoiding running out of memory](@ref optimal_allocation_avoiding_running_out_of_memory)
45
- [Allocation performance](@ref optimal_allocation_allocation_Performance)
46
- [Sub-allocating buffers](@ref optimal_allocation_suballocating_buffers)
47
- [Residency priority](@ref optimal_allocation_residency_priority)
48
- [GPU upload heap](@ref optimal_allocation_gpu_upload_heap)
49
- [Committed versus placed resources](@ref optimal_allocation_committed_vs_placed)
50
- [Resource alignment](@ref optimal_allocation_resource_alignment)
51
- \subpage defragmentation
52
- \subpage statistics
53
- \subpage resource_aliasing
54
- \subpage linear_algorithm
55
- \subpage virtual_allocator
56
- \subpage configuration
57
- [Custom CPU memory allocator](@ref custom_memory_allocator)
58
- [Debug margins](@ref debug_margins)
59
- \subpage general_considerations
60
- [Thread safety](@ref general_considerations_thread_safety)
61
- [Versioning and compatibility](@ref general_considerations_versioning_and_compatibility)
62
- [Features not supported](@ref general_considerations_features_not_supported)
63
64
\section main_see_also Web links
65
66
- [Direct3D 12 Memory Allocator at GPUOpen.com](https://gpuopen.com/gaming-product/d3d12-memory-allocator/) - product page
67
- [GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator at GitHub.com](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator) - source code repository
68
*/
69
70
// If using this library on a platform different than Windows PC or want to use different version of DXGI,
71
// you should include D3D12-compatible headers before this library on your own and define
72
// D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED.
73
// Alternatively, if you are targeting the open sourced DirectX headers, defining D3D12MA_USING_DIRECTX_HEADERS
74
// will include them rather the ones provided by the Windows SDK.
75
#ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
76
#if defined(D3D12MA_USING_DIRECTX_HEADERS)
77
#include <directx/d3d12.h>
78
#include <dxguids/dxguids.h>
79
#else
80
#include <d3d12.h>
81
#endif
82
83
#include <dxgi1_4.h>
84
#endif
85
86
#ifndef D3D12MA_DXGI_1_4
87
#ifdef __IDXGIAdapter3_INTERFACE_DEFINED__
88
/// Define this macro to 0 to disable usage of DXGI 1.4 (which is used for `IDXGIAdapter3` and query for memory budget).
89
#define D3D12MA_DXGI_1_4 1
90
#else
91
#define D3D12MA_DXGI_1_4 0
92
#endif
93
#endif
94
95
#ifndef D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
96
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
97
/// This macro is defined to 0 or 1 automatically. Define it to 0 to disable support for `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED`.
98
#define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 1
99
#else
100
#define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 0
101
#endif
102
#endif
103
104
#ifndef D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
105
/** \brief
106
When defined to value other than 0, the library will try to use
107
`D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT` or `D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT`
108
for created textures when possible, which can save memory because some small textures
109
may get their alignment 4 KB and their size a multiply of 4 KB instead of 64 KB.
110
111
- `#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 0` -
112
Disables small texture alignment.
113
- `#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1` (the default) -
114
Enables conservative algorithm that will use small alignment only for some textures
115
that are surely known to support it.
116
- `#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 2` -
117
Enables query for small alignment to D3D12 (based on Microsoft sample) which will
118
enable small alignment for more textures, but will also generate D3D Debug Layer
119
error #721 on call to `ID3D12Device::GetResourceAllocationInfo`, which you should just
120
ignore.
121
*/
122
#define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1
123
#endif
124
125
#ifndef D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS
126
/// Set of flags recommended for use in D3D12MA::ALLOCATOR_DESC::Flags for optimal performance.
127
#define D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS (ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED)
128
#endif
129
130
#ifndef D3D12MA_RECOMMENDED_HEAP_FLAGS
131
#if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
132
#define D3D12MA_RECOMMENDED_HEAP_FLAGS (D3D12_HEAP_FLAG_CREATE_NOT_ZEROED)
133
#else
134
/// Set of flags recommended for use in D3D12MA::POOL_DESC::HeapFlags for optimal performance.
135
#define D3D12MA_RECOMMENDED_HEAP_FLAGS (D3D12_HEAP_FLAG_NONE)
136
#endif
137
#endif
138
139
#ifndef D3D12MA_RECOMMENDED_POOL_FLAGS
140
/// Set of flags recommended for use in D3D12MA::POOL_DESC::Flags for optimal performance.
141
#define D3D12MA_RECOMMENDED_POOL_FLAGS (POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED)
142
#endif
143
144
145
/// \cond INTERNAL
146
147
#define D3D12MA_CLASS_NO_COPY(className) \
148
private: \
149
className(const className&) = delete; \
150
className(className&&) = delete; \
151
className& operator=(const className&) = delete; \
152
className& operator=(className&&) = delete;
153
154
// To be used with MAKE_HRESULT to define custom error codes.
155
#define FACILITY_D3D12MA 3542
156
157
/*
158
If providing your own implementation, you need to implement a subset of std::atomic.
159
*/
160
#if !defined(D3D12MA_ATOMIC_UINT32) || !defined(D3D12MA_ATOMIC_UINT64)
161
#include <atomic>
162
#endif
163
164
#ifndef D3D12MA_ATOMIC_UINT32
165
#define D3D12MA_ATOMIC_UINT32 std::atomic<UINT>
166
#endif
167
168
#ifndef D3D12MA_ATOMIC_UINT64
169
#define D3D12MA_ATOMIC_UINT64 std::atomic<UINT64>
170
#endif
171
172
#ifdef D3D12MA_EXPORTS
173
#define D3D12MA_API __declspec(dllexport)
174
#elif defined(D3D12MA_IMPORTS)
175
#define D3D12MA_API __declspec(dllimport)
176
#else
177
#define D3D12MA_API
178
#endif
179
180
// Forward declaration if ID3D12ProtectedResourceSession is not defined inside the headers (older SDK, pre ID3D12Device4)
181
struct ID3D12ProtectedResourceSession;
182
183
// Define this enum even if SDK doesn't provide it, to simplify the API.
184
#ifndef __ID3D12Device1_INTERFACE_DEFINED__
185
typedef enum D3D12_RESIDENCY_PRIORITY
186
{
187
D3D12_RESIDENCY_PRIORITY_MINIMUM = 0x28000000,
188
D3D12_RESIDENCY_PRIORITY_LOW = 0x50000000,
189
D3D12_RESIDENCY_PRIORITY_NORMAL = 0x78000000,
190
D3D12_RESIDENCY_PRIORITY_HIGH = 0xa0010000,
191
D3D12_RESIDENCY_PRIORITY_MAXIMUM = 0xc8000000
192
} D3D12_RESIDENCY_PRIORITY;
193
#endif
194
195
namespace D3D12MA
196
{
197
class D3D12MA_API IUnknownImpl : public IUnknown
198
{
199
public:
200
virtual ~IUnknownImpl() = default;
201
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override;
202
ULONG STDMETHODCALLTYPE AddRef() override;
203
ULONG STDMETHODCALLTYPE Release() override;
204
protected:
205
virtual void ReleaseThis() { delete this; }
206
private:
207
D3D12MA_ATOMIC_UINT32 m_RefCount = {1};
208
};
209
} // namespace D3D12MA
210
211
/// \endcond
212
213
namespace D3D12MA
214
{
215
216
/// \cond INTERNAL
217
class DefragmentationContextPimpl;
218
class AllocatorPimpl;
219
class PoolPimpl;
220
class NormalBlock;
221
class BlockVector;
222
class CommittedAllocationList;
223
class JsonWriter;
224
class VirtualBlockPimpl;
225
/// \endcond
226
227
class Pool;
228
class Allocator;
229
struct Statistics;
230
struct DetailedStatistics;
231
struct TotalStatistics;
232
233
/// \brief Unique identifier of single allocation done inside the memory heap.
234
typedef UINT64 AllocHandle;
235
236
/// Pointer to custom callback function that allocates CPU memory.
237
using ALLOCATE_FUNC_PTR = void* (*)(size_t Size, size_t Alignment, void* pPrivateData);
238
/**
239
\brief Pointer to custom callback function that deallocates CPU memory.
240
241
`pMemory = null` should be accepted and ignored.
242
*/
243
using FREE_FUNC_PTR = void (*)(void* pMemory, void* pPrivateData);
244
245
/// Custom callbacks to CPU memory allocation functions.
246
struct ALLOCATION_CALLBACKS
247
{
248
/// %Allocation function.
249
ALLOCATE_FUNC_PTR pAllocate;
250
/// Dellocation function.
251
FREE_FUNC_PTR pFree;
252
/// Custom data that will be passed to allocation and deallocation functions as `pUserData` parameter.
253
void* pPrivateData;
254
};
255
256
257
/// \brief Bit flags to be used with ALLOCATION_DESC::Flags.
258
enum ALLOCATION_FLAGS
259
{
260
/// Zero
261
ALLOCATION_FLAG_NONE = 0,
262
263
/**
264
Set this flag if the allocation should have its own dedicated memory allocation (committed resource with implicit heap).
265
266
Use it for special, big resources, like fullscreen textures used as render targets.
267
268
- When used with functions like D3D12MA::Allocator::CreateResource, it will use `ID3D12Device::CreateCommittedResource`,
269
so the created allocation will contain a resource (D3D12MA::Allocation::GetResource() `!= NULL`) but will not have
270
a heap (D3D12MA::Allocation::GetHeap() `== NULL`), as the heap is implicit.
271
- When used with raw memory allocation like D3D12MA::Allocator::AllocateMemory, it will use `ID3D12Device::CreateHeap`,
272
so the created allocation will contain a heap (D3D12MA::Allocation::GetHeap() `!= NULL`) and its offset will always be 0.
273
*/
274
ALLOCATION_FLAG_COMMITTED = 0x1,
275
276
/**
277
Set this flag to only try to allocate from existing memory heaps and never create new such heap.
278
279
If new allocation cannot be placed in any of the existing heaps, allocation
280
fails with `E_OUTOFMEMORY` error.
281
282
You should not use D3D12MA::ALLOCATION_FLAG_COMMITTED and
283
D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.
284
*/
285
ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2,
286
287
/** Create allocation only if additional memory required for it, if any, won't exceed
288
memory budget. Otherwise return `E_OUTOFMEMORY`.
289
*/
290
ALLOCATION_FLAG_WITHIN_BUDGET = 0x4,
291
292
/** Allocation will be created from upper stack in a double stack pool.
293
294
This flag is only allowed for custom pools created with #POOL_FLAG_ALGORITHM_LINEAR flag.
295
*/
296
ALLOCATION_FLAG_UPPER_ADDRESS = 0x8,
297
298
/** Set this flag if the allocated memory will have aliasing resources.
299
300
Use this when calling D3D12MA::Allocator::CreateResource() and similar to
301
guarantee creation of explicit heap for desired allocation and prevent it from using `CreateCommittedResource`,
302
so that new allocation object will always have `allocation->GetHeap() != NULL`.
303
*/
304
ALLOCATION_FLAG_CAN_ALIAS = 0x10,
305
306
/** %Allocation strategy that chooses smallest possible free range for the allocation
307
to minimize memory usage and fragmentation, possibly at the expense of allocation time.
308
*/
309
ALLOCATION_FLAG_STRATEGY_MIN_MEMORY = 0x00010000,
310
311
/** %Allocation strategy that chooses first suitable free range for the allocation -
312
not necessarily in terms of the smallest offset but the one that is easiest and fastest to find
313
to minimize allocation time, possibly at the expense of allocation quality.
314
*/
315
ALLOCATION_FLAG_STRATEGY_MIN_TIME = 0x00020000,
316
317
/** %Allocation strategy that chooses always the lowest offset in available space.
318
This is not the most efficient strategy but achieves highly packed data.
319
Used internally by defragmentation, not recomended in typical usage.
320
*/
321
ALLOCATION_FLAG_STRATEGY_MIN_OFFSET = 0x0004000,
322
323
/// Alias to #ALLOCATION_FLAG_STRATEGY_MIN_MEMORY.
324
ALLOCATION_FLAG_STRATEGY_BEST_FIT = ALLOCATION_FLAG_STRATEGY_MIN_MEMORY,
325
/// Alias to #ALLOCATION_FLAG_STRATEGY_MIN_TIME.
326
ALLOCATION_FLAG_STRATEGY_FIRST_FIT = ALLOCATION_FLAG_STRATEGY_MIN_TIME,
327
328
/// A bit mask to extract only `STRATEGY` bits from entire set of flags.
329
ALLOCATION_FLAG_STRATEGY_MASK =
330
ALLOCATION_FLAG_STRATEGY_MIN_MEMORY |
331
ALLOCATION_FLAG_STRATEGY_MIN_TIME |
332
ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
333
};
334
335
/// \brief Parameters of created D3D12MA::Allocation object. To be used with Allocator::CreateResource.
336
struct ALLOCATION_DESC
337
{
338
/// Flags for the allocation.
339
ALLOCATION_FLAGS Flags;
340
/** \brief The type of memory heap where the new allocation should be placed.
341
342
It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
343
344
When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
345
*/
346
D3D12_HEAP_TYPE HeapType;
347
/** \brief Additional heap flags to be used when allocating memory.
348
349
In most cases it can be 0.
350
351
- If you use D3D12MA::Allocator::CreateResource(), you don't need to care.
352
Necessary flag `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`, `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
353
or `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES` is added automatically.
354
- If you use D3D12MA::Allocator::AllocateMemory(), you should specify one of those `ALLOW_ONLY` flags.
355
Except when you validate that D3D12MA::Allocator::GetD3D12Options()`.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1` -
356
then you can leave it 0.
357
- You can specify additional flags if needed. Then the memory will always be allocated as
358
separate block using `D3D12Device::CreateCommittedResource` or `CreateHeap`, not as part of an existing larget block.
359
360
When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
361
*/
362
D3D12_HEAP_FLAGS ExtraHeapFlags;
363
/** \brief Custom pool to place the new resource in. Optional.
364
365
When not null, the resource will be created inside specified custom pool.
366
Members `HeapType`, `ExtraHeapFlags` are then ignored.
367
*/
368
Pool* CustomPool;
369
/// Custom general-purpose pointer that will be stored in D3D12MA::Allocation.
370
void* pPrivateData;
371
};
372
373
/** \brief Calculated statistics of memory usage e.g. in a specific memory heap type,
374
memory segment group, custom pool, or total.
375
376
These are fast to calculate.
377
See functions: D3D12MA::Allocator::GetBudget(), D3D12MA::Pool::GetStatistics().
378
*/
379
struct Statistics
380
{
381
/** \brief Number of D3D12 memory blocks allocated - `ID3D12Heap` objects and committed resources.
382
*/
383
UINT BlockCount;
384
/** \brief Number of D3D12MA::Allocation objects allocated.
385
386
Committed allocations have their own blocks, so each one adds 1 to `AllocationCount` as well as `BlockCount`.
387
*/
388
UINT AllocationCount;
389
/** \brief Number of bytes allocated in memory blocks.
390
*/
391
UINT64 BlockBytes;
392
/** \brief Total number of bytes occupied by all D3D12MA::Allocation objects.
393
394
Always less or equal than `BlockBytes`.
395
Difference `(BlockBytes - AllocationBytes)` is the amount of memory allocated from D3D12
396
but unused by any D3D12MA::Allocation.
397
*/
398
UINT64 AllocationBytes;
399
};
400
401
/** \brief More detailed statistics than D3D12MA::Statistics.
402
403
These are slower to calculate. Use for debugging purposes.
404
See functions: D3D12MA::Allocator::CalculateStatistics(), D3D12MA::Pool::CalculateStatistics().
405
406
Averages are not provided because they can be easily calculated as:
407
408
\code
409
UINT64 AllocationSizeAvg = DetailedStats.Statistics.AllocationBytes / detailedStats.Statistics.AllocationCount;
410
UINT64 UnusedBytes = DetailedStats.Statistics.BlockBytes - DetailedStats.Statistics.AllocationBytes;
411
UINT64 UnusedRangeSizeAvg = UnusedBytes / DetailedStats.UnusedRangeCount;
412
\endcode
413
*/
414
struct DetailedStatistics
415
{
416
/// Basic statistics.
417
Statistics Stats;
418
/// Number of free ranges of memory between allocations.
419
UINT UnusedRangeCount;
420
/// Smallest allocation size. `UINT64_MAX` if there are 0 allocations.
421
UINT64 AllocationSizeMin;
422
/// Largest allocation size. 0 if there are 0 allocations.
423
UINT64 AllocationSizeMax;
424
/// Smallest empty range size. `UINT64_MAX` if there are 0 empty ranges.
425
UINT64 UnusedRangeSizeMin;
426
/// Largest empty range size. 0 if there are 0 empty ranges.
427
UINT64 UnusedRangeSizeMax;
428
};
429
430
/** \brief General statistics from current state of the allocator -
431
total memory usage across all memory heaps and segments.
432
433
These are slower to calculate. Use for debugging purposes.
434
See function D3D12MA::Allocator::CalculateStatistics().
435
*/
436
struct TotalStatistics
437
{
438
/** \brief One element for each type of heap located at the following indices:
439
440
- 0 = `D3D12_HEAP_TYPE_DEFAULT`
441
- 1 = `D3D12_HEAP_TYPE_UPLOAD`
442
- 2 = `D3D12_HEAP_TYPE_READBACK`
443
- 3 = `D3D12_HEAP_TYPE_CUSTOM`
444
- 4 = `D3D12_HEAP_TYPE_GPU_UPLOAD`
445
*/
446
DetailedStatistics HeapType[5];
447
/** \brief One element for each memory segment group located at the following indices:
448
449
- 0 = `DXGI_MEMORY_SEGMENT_GROUP_LOCAL`
450
- 1 = `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`
451
452
Meaning of these segment groups is:
453
454
- When `IsUMA() == FALSE` (discrete graphics card):
455
- `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` (index 0) represents GPU memory
456
(resources allocated in `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_GPU_UPLOAD` or `D3D12_MEMORY_POOL_L1`).
457
- `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL` (index 1) represents system memory
458
(resources allocated in `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`, or `D3D12_MEMORY_POOL_L0`).
459
- When `IsUMA() == TRUE` (integrated graphics chip):
460
- `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` = (index 0) represents memory shared for all the resources.
461
- `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL` = (index 1) is unused and always 0.
462
*/
463
DetailedStatistics MemorySegmentGroup[2];
464
/// Total statistics from all memory allocated from D3D12.
465
DetailedStatistics Total;
466
};
467
468
/** \brief %Statistics of current memory usage and available budget for a specific memory segment group.
469
470
These are fast to calculate. See function D3D12MA::Allocator::GetBudget().
471
*/
472
struct Budget
473
{
474
/** \brief %Statistics fetched from the library.
475
*/
476
Statistics Stats;
477
/** \brief Estimated current memory usage of the program.
478
479
Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if possible.
480
481
It might be different than `BlockBytes` (usually higher) due to additional implicit objects
482
also occupying the memory, like swapchain, pipeline state objects, descriptor heaps, command lists, or
483
heaps and resources allocated outside of this library, if any.
484
*/
485
UINT64 UsageBytes;
486
/** \brief Estimated amount of memory available to the program.
487
488
Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if possible.
489
490
It might be different (most probably smaller) than memory capacity returned
491
by D3D12MA::Allocator::GetMemoryCapacity() due to factors
492
external to the program, decided by the operating system.
493
Difference `BudgetBytes - UsageBytes` is the amount of additional memory that can probably
494
be allocated without problems. Exceeding the budget may result in various problems.
495
*/
496
UINT64 BudgetBytes;
497
};
498
499
500
/// \brief Represents single memory allocation done inside VirtualBlock.
501
struct D3D12MA_API VirtualAllocation
502
{
503
/// \brief Unique idenitfier of current allocation. 0 means null/invalid.
504
AllocHandle AllocHandle;
505
};
506
507
/** \brief Represents single memory allocation.
508
509
It may be either implicit memory heap dedicated to a single resource or a
510
specific region of a bigger heap plus unique offset.
511
512
To create such object, fill structure D3D12MA::ALLOCATION_DESC and call function
513
Allocator::CreateResource.
514
515
The object remembers size and some other information.
516
To retrieve this information, use methods of this class.
517
518
The object also remembers `ID3D12Resource` and "owns" a reference to it,
519
so it calls `%Release()` on the resource when destroyed.
520
*/
521
class D3D12MA_API Allocation : public IUnknownImpl
522
{
523
public:
524
/** \brief Returns offset in bytes from the start of memory heap.
525
526
You usually don't need to use this offset. If you create a buffer or a texture together with the allocation using function
527
D3D12MA::Allocator::CreateResource, functions that operate on that resource refer to the beginning of the resource,
528
not entire memory heap.
529
530
If the Allocation represents committed resource with implicit heap, returns 0.
531
*/
532
UINT64 GetOffset() const;
533
534
/// Returns alignment that resource was created with.
535
UINT64 GetAlignment() const { return m_Alignment; }
536
537
/** \brief Returns size in bytes of the allocation.
538
539
- If you created a buffer or a texture together with the allocation using function D3D12MA::Allocator::CreateResource,
540
this is the size of the resource returned by `ID3D12Device::GetResourceAllocationInfo`.
541
- For allocations made out of bigger memory blocks, this also is the size of the memory region assigned exclusively to this allocation.
542
- For resources created as committed, this value may not be accurate. DirectX implementation may optimize memory usage internally
543
so that you may even observe regions of `ID3D12Resource::GetGPUVirtualAddress()` + Allocation::GetSize() to overlap in memory and still work correctly.
544
*/
545
UINT64 GetSize() const { return m_Size; }
546
547
/** \brief Returns D3D12 resource associated with this object.
548
549
Calling this method doesn't increment resource's reference counter.
550
*/
551
ID3D12Resource* GetResource() const { return m_Resource; }
552
553
/** \brief Releases the resource currently pointed by the allocation (if not null), sets it to new one, incrementing its reference counter (if not null).
554
555
\warning
556
This is an advanced feature that should be used only in special cases, e.g. during \subpage defragmentation.
557
Typically, an allocation object should reference the resource that was created together with it.
558
If you swap it to another resource of different size, \subpage statistics and budgets can be calculated incorrectly.
559
*/
560
void SetResource(ID3D12Resource* pResource);
561
562
/** \brief Returns memory heap that the resource is created in.
563
564
If the Allocation represents committed resource with implicit heap, returns NULL.
565
*/
566
ID3D12Heap* GetHeap() const;
567
568
/// Changes custom pointer for an allocation to a new value.
569
void SetPrivateData(void* pPrivateData) { m_pPrivateData = pPrivateData; }
570
571
/// Get custom pointer associated with the allocation.
572
void* GetPrivateData() const { return m_pPrivateData; }
573
574
/** \brief Associates a name with the allocation object. This name is for use in debug diagnostics and tools.
575
576
Internal copy of the string is made, so the memory pointed by the argument can be
577
changed of freed immediately after this call.
578
579
`Name` can be null.
580
*/
581
void SetName(LPCWSTR Name);
582
583
/** \brief Returns the name associated with the allocation object.
584
585
Returned string points to an internal copy.
586
587
If no name was associated with the allocation, returns null.
588
*/
589
LPCWSTR GetName() const { return m_Name; }
590
591
protected:
592
void ReleaseThis() override;
593
594
private:
595
friend class AllocatorPimpl;
596
friend class BlockVector;
597
friend class CommittedAllocationList;
598
friend class JsonWriter;
599
friend class BlockMetadata_Linear;
600
friend class DefragmentationContextPimpl;
601
friend struct CommittedAllocationListItemTraits;
602
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
603
template<typename T> friend class PoolAllocator;
604
605
enum Type
606
{
607
TYPE_COMMITTED,
608
TYPE_PLACED,
609
TYPE_HEAP,
610
TYPE_COUNT
611
};
612
613
AllocatorPimpl* m_Allocator;
614
UINT64 m_Size;
615
UINT64 m_Alignment;
616
ID3D12Resource* m_Resource;
617
void* m_pPrivateData;
618
wchar_t* m_Name;
619
620
union
621
{
622
struct
623
{
624
CommittedAllocationList* list;
625
Allocation* prev;
626
Allocation* next;
627
} m_Committed;
628
629
struct
630
{
631
AllocHandle allocHandle;
632
NormalBlock* block;
633
} m_Placed;
634
635
struct
636
{
637
// Beginning must be compatible with m_Committed.
638
CommittedAllocationList* list;
639
Allocation* prev;
640
Allocation* next;
641
ID3D12Heap* heap;
642
} m_Heap;
643
};
644
645
struct PackedData
646
{
647
public:
648
PackedData() :
649
m_Type(0), m_ResourceDimension(0), m_ResourceFlags(0), m_TextureLayout(0) { }
650
651
Type GetType() const { return (Type)m_Type; }
652
D3D12_RESOURCE_DIMENSION GetResourceDimension() const { return (D3D12_RESOURCE_DIMENSION)m_ResourceDimension; }
653
D3D12_RESOURCE_FLAGS GetResourceFlags() const { return (D3D12_RESOURCE_FLAGS)m_ResourceFlags; }
654
D3D12_TEXTURE_LAYOUT GetTextureLayout() const { return (D3D12_TEXTURE_LAYOUT)m_TextureLayout; }
655
656
void SetType(Type type);
657
void SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension);
658
void SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags);
659
void SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout);
660
661
private:
662
UINT m_Type : 2; // enum Type
663
UINT m_ResourceDimension : 3; // enum D3D12_RESOURCE_DIMENSION
664
UINT m_ResourceFlags : 24; // flags D3D12_RESOURCE_FLAGS
665
UINT m_TextureLayout : 9; // enum D3D12_TEXTURE_LAYOUT
666
} m_PackedData;
667
668
Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment);
669
// Nothing here, everything already done in Release.
670
virtual ~Allocation() = default;
671
672
void InitCommitted(CommittedAllocationList* list);
673
void InitPlaced(AllocHandle allocHandle, NormalBlock* block);
674
void InitHeap(CommittedAllocationList* list, ID3D12Heap* heap);
675
void SwapBlockAllocation(Allocation* allocation);
676
// If the Allocation represents committed resource with implicit heap, returns UINT64_MAX.
677
AllocHandle GetAllocHandle() const;
678
NormalBlock* GetBlock();
679
template<typename D3D12_RESOURCE_DESC_T>
680
void SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc);
681
void FreeName();
682
683
D3D12MA_CLASS_NO_COPY(Allocation)
684
};
685
686
687
/// Flags to be passed as DEFRAGMENTATION_DESC::Flags.
688
enum DEFRAGMENTATION_FLAGS
689
{
690
/** Use simple but fast algorithm for defragmentation.
691
May not achieve best results but will require least time to compute and least allocations to copy.
692
*/
693
DEFRAGMENTATION_FLAG_ALGORITHM_FAST = 0x1,
694
/** Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified.
695
Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved.
696
*/
697
DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED = 0x2,
698
/** Perform full defragmentation of memory.
699
Can result in notably more time to compute and allocations to copy, but will achieve best memory packing.
700
*/
701
DEFRAGMENTATION_FLAG_ALGORITHM_FULL = 0x4,
702
703
/// A bit mask to extract only `ALGORITHM` bits from entire set of flags.
704
DEFRAGMENTATION_FLAG_ALGORITHM_MASK =
705
DEFRAGMENTATION_FLAG_ALGORITHM_FAST |
706
DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED |
707
DEFRAGMENTATION_FLAG_ALGORITHM_FULL
708
};
709
710
/** \brief Parameters for defragmentation.
711
712
To be used with functions Allocator::BeginDefragmentation() and Pool::BeginDefragmentation().
713
*/
714
struct DEFRAGMENTATION_DESC
715
{
716
/// Flags.
717
DEFRAGMENTATION_FLAGS Flags;
718
/** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places.
719
720
0 means no limit.
721
*/
722
UINT64 MaxBytesPerPass;
723
/** \brief Maximum number of allocations that can be moved during single pass to a different place.
724
725
0 means no limit.
726
*/
727
UINT32 MaxAllocationsPerPass;
728
};
729
730
/// Operation performed on single defragmentation move.
731
enum DEFRAGMENTATION_MOVE_OPERATION
732
{
733
/** Resource has been recreated at `pDstTmpAllocation`, data has been copied, old resource has been destroyed.
734
`pSrcAllocation` will be changed to point to the new place. This is the default value set by DefragmentationContext::BeginPass().
735
*/
736
DEFRAGMENTATION_MOVE_OPERATION_COPY = 0,
737
/// Set this value if you cannot move the allocation. New place reserved at `pDstTmpAllocation` will be freed. `pSrcAllocation` will remain unchanged.
738
DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1,
739
/// 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`.
740
DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2,
741
};
742
743
/// Single move of an allocation to be done for defragmentation.
744
struct DEFRAGMENTATION_MOVE
745
{
746
/** \brief Operation to be performed on the allocation by DefragmentationContext::EndPass().
747
Default value is #DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.
748
*/
749
DEFRAGMENTATION_MOVE_OPERATION Operation;
750
/// %Allocation that should be moved.
751
Allocation* pSrcAllocation;
752
/** \brief Temporary allocation pointing to destination memory that will replace `pSrcAllocation`.
753
754
Use it to retrieve new `ID3D12Heap` and offset to create new `ID3D12Resource` and then store it here via Allocation::SetResource().
755
756
\warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass,
757
to be used for storing newly created resource. DefragmentationContext::EndPass() will destroy it and make `pSrcAllocation` point to this memory.
758
*/
759
Allocation* pDstTmpAllocation;
760
};
761
762
/** \brief Parameters for incremental defragmentation steps.
763
764
To be used with function DefragmentationContext::BeginPass().
765
*/
766
struct DEFRAGMENTATION_PASS_MOVE_INFO
767
{
768
/// Number of elements in the `pMoves` array.
769
UINT32 MoveCount;
770
/** \brief Array of moves to be performed by the user in the current defragmentation pass.
771
772
Pointer to an array of `MoveCount` elements, owned by %D3D12MA, created in DefragmentationContext::BeginPass(), destroyed in DefragmentationContext::EndPass().
773
774
For each element, you should:
775
776
1. Create a new resource in the place pointed by `pMoves[i].pDstTmpAllocation->GetHeap()` + `pMoves[i].pDstTmpAllocation->GetOffset()`.
777
2. Store new resource in `pMoves[i].pDstTmpAllocation` by using Allocation::SetResource(). It will later replace old resource from `pMoves[i].pSrcAllocation`.
778
3. Copy data from the `pMoves[i].pSrcAllocation` e.g. using `D3D12GraphicsCommandList::CopyResource`.
779
4. Make sure these commands finished executing on the GPU.
780
781
Only then you can finish defragmentation pass by calling DefragmentationContext::EndPass().
782
After this call, the allocation will point to the new place in memory.
783
784
Alternatively, if you cannot move specific allocation,
785
you can set DEFRAGMENTATION_MOVE::Operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
786
787
Alternatively, if you decide you want to completely remove the allocation,
788
set DEFRAGMENTATION_MOVE::Operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY.
789
Then, after DefragmentationContext::EndPass() the allocation will be released.
790
*/
791
DEFRAGMENTATION_MOVE* pMoves;
792
};
793
794
/// %Statistics returned for defragmentation process by function DefragmentationContext::GetStats().
795
struct DEFRAGMENTATION_STATS
796
{
797
/// Total number of bytes that have been copied while moving allocations to different places.
798
UINT64 BytesMoved;
799
/// Total number of bytes that have been released to the system by freeing empty heaps.
800
UINT64 BytesFreed;
801
/// Number of allocations that have been moved to different places.
802
UINT32 AllocationsMoved;
803
/// Number of empty `ID3D12Heap` objects that have been released to the system.
804
UINT32 HeapsFreed;
805
};
806
807
/** \brief Represents defragmentation process in progress.
808
809
You can create this object using Allocator::BeginDefragmentation (for default pools) or
810
Pool::BeginDefragmentation (for a custom pool).
811
*/
812
class D3D12MA_API DefragmentationContext : public IUnknownImpl
813
{
814
public:
815
/** \brief Starts single defragmentation pass.
816
817
\param[out] pPassInfo Computed informations for current pass.
818
\returns
819
- `S_OK` if no more moves are possible. Then you can omit call to DefragmentationContext::EndPass() and simply end whole defragmentation.
820
- `S_FALSE` if there are pending moves returned in `pPassInfo`. You need to perform them, call DefragmentationContext::EndPass(),
821
and then preferably try another pass with DefragmentationContext::BeginPass().
822
*/
823
HRESULT BeginPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo);
824
/** \brief Ends single defragmentation pass.
825
826
\param pPassInfo Computed informations for current pass filled by DefragmentationContext::BeginPass() and possibly modified by you.
827
\return Returns `S_OK` if no more moves are possible or `S_FALSE` if more defragmentations are possible.
828
829
Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`.
830
After this call:
831
832
- %Allocation at `pPassInfo[i].pSrcAllocation` that had `pPassInfo[i].Operation ==` #DEFRAGMENTATION_MOVE_OPERATION_COPY
833
(which is the default) will be pointing to the new destination place.
834
- %Allocation at `pPassInfo[i].pSrcAllocation` that had `pPassInfo[i].operation ==` #DEFRAGMENTATION_MOVE_OPERATION_DESTROY
835
will be released.
836
837
If no more moves are possible you can end whole defragmentation.
838
*/
839
HRESULT EndPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo);
840
/** \brief Returns statistics of the defragmentation performed so far.
841
*/
842
void GetStats(DEFRAGMENTATION_STATS* pStats);
843
844
protected:
845
void ReleaseThis() override;
846
847
private:
848
friend class Pool;
849
friend class Allocator;
850
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
851
852
DefragmentationContextPimpl* m_Pimpl;
853
854
DefragmentationContext(AllocatorPimpl* allocator,
855
const DEFRAGMENTATION_DESC& desc,
856
BlockVector* poolVector);
857
~DefragmentationContext();
858
859
D3D12MA_CLASS_NO_COPY(DefragmentationContext)
860
};
861
862
/// \brief Bit flags to be used with POOL_DESC::Flags.
863
enum POOL_FLAGS
864
{
865
/// Zero
866
POOL_FLAG_NONE = 0,
867
868
/** Enables alternative, linear allocation algorithm in this pool.
869
870
Specify this flag to enable linear allocation algorithm, which always creates
871
new allocations after last one and doesn't reuse space from allocations freed in
872
between. It trades memory consumption for simplified algorithm and data
873
structure, which has better performance and uses less memory for metadata.
874
875
By using this flag, you can achieve behavior of free-at-once, stack,
876
ring buffer, and double stack.
877
For details, see documentation chapter \ref linear_algorithm.
878
*/
879
POOL_FLAG_ALGORITHM_LINEAR = 0x1,
880
881
/** Optimization, allocate MSAA textures as committed resources always.
882
883
Specify this flag to create MSAA textures with implicit heaps, as if they were created
884
with flag D3D12MA::ALLOCATION_FLAG_COMMITTED. Usage of this flags enables pool to create its heaps
885
on smaller alignment not suitable for MSAA textures.
886
887
You should always use this flag unless you really need to create some MSAA textures in this pool as placed.
888
*/
889
POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x2,
890
/** Every allocation made in this pool will be created as a committed resource - will have its own memory block.
891
892
There is also an equivalent flag for the entire allocator: D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED.
893
*/
894
POOL_FLAG_ALWAYS_COMMITTED = 0x4,
895
896
// Bit mask to extract only `ALGORITHM` bits from entire set of flags.
897
POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_LINEAR
898
};
899
900
/// \brief Parameters of created D3D12MA::Pool object. To be used with D3D12MA::Allocator::CreatePool.
901
struct POOL_DESC
902
{
903
/** \brief Flags for the heap.
904
905
It is recommended to use #D3D12MA_RECOMMENDED_HEAP_FLAGS.
906
*/
907
POOL_FLAGS Flags;
908
/** \brief The parameters of memory heap where allocations of this pool should be placed.
909
910
In the simplest case, just fill it with zeros and set `Type` to one of: `D3D12_HEAP_TYPE_DEFAULT`,
911
`D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`. Additional parameters can be used e.g. to utilize UMA.
912
*/
913
D3D12_HEAP_PROPERTIES HeapProperties;
914
/** \brief Heap flags to be used when allocating heaps of this pool.
915
916
It should contain one of these values, depending on type of resources you are going to create in this heap:
917
`D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
918
`D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
919
`D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
920
Except if ResourceHeapTier = 2, then it may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
921
922
It is recommended to also add #D3D12MA_RECOMMENDED_POOL_FLAGS.
923
You can specify additional flags if needed.
924
*/
925
D3D12_HEAP_FLAGS HeapFlags;
926
/** \brief Size of a single heap (memory block) to be allocated as part of this pool, in bytes. Optional.
927
928
Specify nonzero to set explicit, constant size of memory blocks used by this pool.
929
Leave 0 to use default and let the library manage block sizes automatically.
930
Then sizes of particular blocks may vary.
931
*/
932
UINT64 BlockSize;
933
/** \brief Minimum number of heaps (memory blocks) to be always allocated in this pool, even if they stay empty. Optional.
934
935
Set to 0 to have no preallocated blocks and allow the pool be completely empty.
936
*/
937
UINT MinBlockCount;
938
/** \brief Maximum number of heaps (memory blocks) that can be allocated in this pool. Optional.
939
940
Set to 0 to use default, which is `UINT64_MAX`, which means no limit.
941
942
Set to same value as D3D12MA::POOL_DESC::MinBlockCount to have fixed amount of memory allocated
943
throughout whole lifetime of this pool.
944
*/
945
UINT MaxBlockCount;
946
/** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0.
947
948
Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two.
949
*/
950
UINT64 MinAllocationAlignment;
951
/** \brief Additional parameter allowing pool to create resources with passed protected session.
952
953
If not null then all the heaps and committed resources will be created with this parameter.
954
Valid only if ID3D12Device4 interface is present in current Windows SDK!
955
*/
956
ID3D12ProtectedResourceSession* pProtectedSession;
957
/** \brief Residency priority to be set for all allocations made in this pool. Optional.
958
959
Set this parameter to one of the possible enum values e.g. `D3D12_RESIDENCY_PRIORITY_HIGH`
960
to apply specific residency priority to all allocations made in this pool:
961
`ID3D12Heap` memory blocks used to sub-allocate for placed resources, as well as
962
committed resources or heaps created when D3D12MA::ALLOCATION_FLAG_COMMITTED is used.
963
This can increase/decrease chance that the memory will be pushed out from VRAM
964
to system RAM when the system runs out of memory, which is invisible to the developer
965
using D3D12 API while it can degrade performance.
966
967
Priority is set using function `ID3D12Device1::SetResidencyPriority`.
968
It is performed only when `ID3D12Device1` interface is defined and successfully obtained.
969
Otherwise, this parameter is ignored.
970
971
This parameter is optional. If you set it to `D3D12_RESIDENCY_PRIORITY(0)`,
972
residency priority will not be set for allocations made in this pool.
973
974
There is no equivalent parameter for allocations made in default pools.
975
If you want to set residency priority for such allocation, you need to do it manually:
976
allocate with D3D12MA::ALLOCATION_FLAG_COMMITTED and call
977
`ID3D12Device1::SetResidencyPriority`, passing `allocation->GetResource()`.
978
*/
979
D3D12_RESIDENCY_PRIORITY ResidencyPriority;
980
};
981
982
/** \brief Custom memory pool
983
984
Represents a separate set of heaps (memory blocks) that can be used to create
985
D3D12MA::Allocation-s and resources in it. Usually there is no need to create custom
986
pools - creating resources in default pool is sufficient.
987
988
To create custom pool, fill D3D12MA::POOL_DESC and call D3D12MA::Allocator::CreatePool.
989
*/
990
class D3D12MA_API Pool : public IUnknownImpl
991
{
992
public:
993
/** \brief Returns copy of parameters of the pool.
994
995
These are the same parameters as passed to D3D12MA::Allocator::CreatePool.
996
*/
997
POOL_DESC GetDesc() const;
998
999
/** \brief Retrieves basic statistics of the custom pool that are fast to calculate.
1000
1001
\param[out] pStats %Statistics of the current pool.
1002
*/
1003
void GetStatistics(Statistics* pStats);
1004
1005
/** \brief Retrieves detailed statistics of the custom pool that are slower to calculate.
1006
1007
\param[out] pStats %Statistics of the current pool.
1008
*/
1009
void CalculateStatistics(DetailedStatistics* pStats);
1010
1011
/** \brief Associates a name with the pool. This name is for use in debug diagnostics and tools.
1012
1013
Internal copy of the string is made, so the memory pointed by the argument can be
1014
changed of freed immediately after this call.
1015
1016
`Name` can be NULL.
1017
*/
1018
void SetName(LPCWSTR Name);
1019
1020
/** \brief Returns the name associated with the pool object.
1021
1022
Returned string points to an internal copy.
1023
1024
If no name was associated with the allocation, returns NULL.
1025
*/
1026
LPCWSTR GetName() const;
1027
1028
/** \brief Begins defragmentation process of the current pool.
1029
1030
\param pDesc Structure filled with parameters of defragmentation.
1031
\param[out] ppContext Context object that will manage defragmentation.
1032
\returns
1033
- `S_OK` if defragmentation can begin.
1034
- `E_NOINTERFACE` if defragmentation is not supported.
1035
1036
For more information about defragmentation, see documentation chapter:
1037
[Defragmentation](@ref defragmentation).
1038
*/
1039
HRESULT BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext);
1040
1041
protected:
1042
void ReleaseThis() override;
1043
1044
private:
1045
friend class Allocator;
1046
friend class AllocatorPimpl;
1047
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
1048
1049
PoolPimpl* m_Pimpl;
1050
1051
Pool(Allocator* allocator, const POOL_DESC &desc);
1052
~Pool();
1053
1054
D3D12MA_CLASS_NO_COPY(Pool)
1055
};
1056
1057
1058
/// \brief Bit flags to be used with ALLOCATOR_DESC::Flags.
1059
enum ALLOCATOR_FLAGS
1060
{
1061
/// Zero
1062
ALLOCATOR_FLAG_NONE = 0,
1063
1064
/**
1065
Allocator and all objects created from it will not be synchronized internally,
1066
so you must guarantee they are used from only one thread at a time or
1067
synchronized by you.
1068
1069
Using this flag may increase performance because internal mutexes are not used.
1070
*/
1071
ALLOCATOR_FLAG_SINGLETHREADED = 0x1,
1072
1073
/** Every allocation will be created as a committed resource - will have its own memory block.
1074
1075
Affects both default pools and custom pools.
1076
To be used for debugging purposes only.
1077
There is also an equivalent flag for custom pools: D3D12MA::POOL_FLAG_ALWAYS_COMMITTED.
1078
*/
1079
ALLOCATOR_FLAG_ALWAYS_COMMITTED = 0x2,
1080
1081
/**
1082
Heaps created for the default pools will be created with flag `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED`,
1083
allowing for their memory to be not zeroed by the system if possible,
1084
which can speed up allocation.
1085
1086
Only affects default pools.
1087
To use the flag with @ref custom_pools, you need to add it manually:
1088
1089
\code
1090
poolDesc.heapFlags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
1091
\endcode
1092
1093
Only avaiable if `ID3D12Device8` is present. Otherwise, the flag is ignored.
1094
*/
1095
ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED = 0x4,
1096
1097
/** Optimization, allocate MSAA textures as committed resources always.
1098
1099
Specify this flag to create MSAA textures with implicit heaps, as if they were created
1100
with flag D3D12MA::ALLOCATION_FLAG_COMMITTED. Usage of this flags enables all default pools
1101
to create its heaps on smaller alignment not suitable for MSAA textures.
1102
1103
You should always use this flag unless you really need to create some MSAA textures as placed.
1104
*/
1105
ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x8,
1106
/** Disable optimization that prefers creating small buffers as committed to avoid 64 KB alignment.
1107
1108
By default, the library prefers creating small buffers <= 32 KB as committed,
1109
because drivers tend to pack them better, while placed buffers require 64 KB alignment.
1110
This, however, may decrease performance, as creating committed resources involves allocation of implicit heaps,
1111
which may take longer than creating placed resources in existing heaps.
1112
Passing this flag will disable this committed preference globally for the allocator.
1113
It can also be disabled for a single allocation by using #ALLOCATION_FLAG_STRATEGY_MIN_TIME.
1114
*/
1115
ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED = 0x10,
1116
};
1117
1118
/// \brief Parameters of created Allocator object. To be used with CreateAllocator().
1119
struct ALLOCATOR_DESC
1120
{
1121
/** \brief Flags for the entire allocator.
1122
1123
It is recommended to use #D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS.
1124
*/
1125
ALLOCATOR_FLAGS Flags;
1126
1127
/** Direct3D device object that the allocator should be attached to.
1128
1129
Allocator is doing `AddRef`/`Release` on this object.
1130
*/
1131
ID3D12Device* pDevice;
1132
1133
/** \brief Preferred size of a single `ID3D12Heap` block to be allocated.
1134
1135
Set to 0 to use default, which is currently 64 MiB.
1136
*/
1137
UINT64 PreferredBlockSize;
1138
1139
/** \brief Custom CPU memory allocation callbacks. Optional.
1140
1141
Optional, can be null. When specified, will be used for all CPU-side memory allocations.
1142
*/
1143
const ALLOCATION_CALLBACKS* pAllocationCallbacks;
1144
1145
/** DXGI Adapter object that you use for D3D12 and this allocator.
1146
1147
Allocator is doing `AddRef`/`Release` on this object.
1148
*/
1149
IDXGIAdapter* pAdapter;
1150
};
1151
1152
/**
1153
\brief Represents main object of this library initialized for particular `ID3D12Device`.
1154
1155
Fill structure D3D12MA::ALLOCATOR_DESC and call function CreateAllocator() to create it.
1156
Call method `Release()` to destroy it.
1157
1158
It is recommended to create just one object of this type per `ID3D12Device` object,
1159
right after Direct3D 12 is initialized and keep it alive until before Direct3D device is destroyed.
1160
*/
1161
class D3D12MA_API Allocator : public IUnknownImpl
1162
{
1163
public:
1164
/// Returns cached options retrieved from D3D12 device.
1165
const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const;
1166
/** \brief Returns true if `D3D12_FEATURE_DATA_ARCHITECTURE1::UMA` was found to be true.
1167
1168
For more information about how to use it, see articles in Microsoft Docs articles:
1169
1170
- "UMA Optimizations: CPU Accessible Textures and Standard Swizzle"
1171
- "D3D12_FEATURE_DATA_ARCHITECTURE structure (d3d12.h)"
1172
- "ID3D12Device::GetCustomHeapProperties method (d3d12.h)"
1173
*/
1174
BOOL IsUMA() const;
1175
/** \brief Returns true if `D3D12_FEATURE_DATA_ARCHITECTURE1::CacheCoherentUMA` was found to be true.
1176
1177
For more information about how to use it, see articles in Microsoft Docs articles:
1178
1179
- "UMA Optimizations: CPU Accessible Textures and Standard Swizzle"
1180
- "D3D12_FEATURE_DATA_ARCHITECTURE structure (d3d12.h)"
1181
- "ID3D12Device::GetCustomHeapProperties method (d3d12.h)"
1182
*/
1183
BOOL IsCacheCoherentUMA() const;
1184
/** \brief Returns true if GPU Upload Heaps are supported on the current system.
1185
1186
When true, you can use `D3D12_HEAP_TYPE_GPU_UPLOAD`.
1187
1188
This flag is fetched from `D3D12_FEATURE_D3D12_OPTIONS16::GPUUploadHeapSupported`.
1189
*/
1190
BOOL IsGPUUploadHeapSupported() const;
1191
/** \brief Returns total amount of memory of specific segment group, in bytes.
1192
1193
\param memorySegmentGroup use `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` or `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`.
1194
1195
This information is taken from `DXGI_ADAPTER_DESC`.
1196
It is not recommended to use this number.
1197
You should preferably call GetBudget() and limit memory usage to D3D12MA::Budget::BudgetBytes instead.
1198
1199
- When IsUMA() `== FALSE` (discrete graphics card):
1200
- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)` returns the size of the video memory.
1201
- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)` returns the size of the system memory available for D3D12 resources.
1202
- When IsUMA() `== TRUE` (integrated graphics chip):
1203
- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)` returns the size of the shared memory available for all D3D12 resources.
1204
All memory is considered "local".
1205
- `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)` is not applicable and returns 0.
1206
*/
1207
UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;
1208
1209
/** \brief Allocates memory and creates a D3D12 resource (buffer or texture). This is the main allocation function.
1210
1211
The function is similar to `ID3D12Device::CreateCommittedResource`, but it may
1212
really call `ID3D12Device::CreatePlacedResource` to assign part of a larger,
1213
existing memory heap to the new resource, which is the main purpose of this
1214
whole library.
1215
1216
If `ppvResource` is null, you receive only `ppAllocation` object from this function.
1217
It holds pointer to `ID3D12Resource` that can be queried using function D3D12MA::Allocation::GetResource().
1218
Reference count of the resource object is 1.
1219
It is automatically destroyed when you destroy the allocation object.
1220
1221
If `ppvResource` is not null, you receive pointer to the resource next to allocation object.
1222
Reference count of the resource object is then increased by calling `QueryInterface`, so you need to manually `Release` it
1223
along with the allocation.
1224
1225
\param pAllocDesc Parameters of the allocation.
1226
\param pResourceDesc Description of created resource.
1227
\param InitialResourceState Initial resource state.
1228
\param pOptimizedClearValue Optional. Either null or optimized clear value.
1229
\param[out] ppAllocation Filled with pointer to new allocation object created.
1230
\param riidResource IID of a resource to be returned via `ppvResource`.
1231
\param[out] ppvResource Optional. If not null, filled with pointer to new resouce created.
1232
1233
\note This function creates a new resource. Sub-allocation of parts of one large buffer,
1234
although recommended as a good practice, is out of scope of this library and could be implemented
1235
by the user as a higher-level logic on top of it, e.g. using the \ref virtual_allocator feature.
1236
*/
1237
HRESULT CreateResource(
1238
const ALLOCATION_DESC* pAllocDesc,
1239
const D3D12_RESOURCE_DESC* pResourceDesc,
1240
D3D12_RESOURCE_STATES InitialResourceState,
1241
const D3D12_CLEAR_VALUE *pOptimizedClearValue,
1242
Allocation** ppAllocation,
1243
REFIID riidResource,
1244
void** ppvResource);
1245
1246
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
1247
/** \brief Similar to Allocator::CreateResource, but supports new structure `D3D12_RESOURCE_DESC1`.
1248
1249
It internally uses `ID3D12Device8::CreateCommittedResource2` or `ID3D12Device8::CreatePlacedResource1`.
1250
1251
To work correctly, `ID3D12Device8` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
1252
*/
1253
HRESULT CreateResource2(
1254
const ALLOCATION_DESC* pAllocDesc,
1255
const D3D12_RESOURCE_DESC1* pResourceDesc,
1256
D3D12_RESOURCE_STATES InitialResourceState,
1257
const D3D12_CLEAR_VALUE *pOptimizedClearValue,
1258
Allocation** ppAllocation,
1259
REFIID riidResource,
1260
void** ppvResource);
1261
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
1262
1263
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
1264
/** \brief Similar to Allocator::CreateResource2, but there are initial layout instead of state and
1265
castable formats list
1266
1267
It internally uses `ID3D12Device10::CreateCommittedResource3` or `ID3D12Device10::CreatePlacedResource2`.
1268
1269
To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
1270
*/
1271
HRESULT CreateResource3(const ALLOCATION_DESC* pAllocDesc,
1272
const D3D12_RESOURCE_DESC1* pResourceDesc,
1273
D3D12_BARRIER_LAYOUT InitialLayout,
1274
const D3D12_CLEAR_VALUE* pOptimizedClearValue,
1275
UINT32 NumCastableFormats,
1276
DXGI_FORMAT* pCastableFormats,
1277
Allocation** ppAllocation,
1278
REFIID riidResource,
1279
void** ppvResource);
1280
#endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
1281
1282
/** \brief Allocates memory without creating any resource placed in it.
1283
1284
This function is similar to `ID3D12Device::CreateHeap`, but it may really assign
1285
part of a larger, existing heap to the allocation.
1286
1287
`pAllocDesc->heapFlags` should contain one of these values, depending on type of resources you are going to create in this memory:
1288
`D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
1289
`D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
1290
`D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
1291
Except if you validate that ResourceHeapTier = 2 - then `heapFlags`
1292
may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
1293
Additional flags in `heapFlags` are allowed as well.
1294
1295
`pAllocInfo->SizeInBytes` must be multiply of 64KB.
1296
`pAllocInfo->Alignment` must be one of the legal values as described in documentation of `D3D12_HEAP_DESC`.
1297
1298
If you use D3D12MA::ALLOCATION_FLAG_COMMITTED you will get a separate memory block -
1299
a heap that always has offset 0.
1300
*/
1301
HRESULT AllocateMemory(
1302
const ALLOCATION_DESC* pAllocDesc,
1303
const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
1304
Allocation** ppAllocation);
1305
1306
/** \brief Creates a new resource in place of an existing allocation. This is useful for memory aliasing.
1307
1308
\param pAllocation Existing allocation indicating the memory where the new resource should be created.
1309
It can be created using D3D12MA::Allocator::CreateResource and already have a resource bound to it,
1310
or can be a raw memory allocated with D3D12MA::Allocator::AllocateMemory.
1311
It must not be created as committed so that `ID3D12Heap` is available and not implicit.
1312
\param AllocationLocalOffset Additional offset in bytes to be applied when allocating the resource.
1313
Local from the start of `pAllocation`, not the beginning of the whole `ID3D12Heap`!
1314
If the new resource should start from the beginning of the `pAllocation` it should be 0.
1315
\param pResourceDesc Description of the new resource to be created.
1316
\param InitialResourceState
1317
\param pOptimizedClearValue
1318
\param riidResource
1319
\param[out] ppvResource Returns pointer to the new resource.
1320
The resource is not bound with `pAllocation`.
1321
This pointer must not be null - you must get the resource pointer and `Release` it when no longer needed.
1322
1323
Memory requirements of the new resource are checked for validation.
1324
If its size exceeds the end of `pAllocation` or required alignment is not fulfilled
1325
considering `pAllocation->GetOffset() + AllocationLocalOffset`, the function
1326
returns `E_INVALIDARG`.
1327
*/
1328
HRESULT CreateAliasingResource(
1329
Allocation* pAllocation,
1330
UINT64 AllocationLocalOffset,
1331
const D3D12_RESOURCE_DESC* pResourceDesc,
1332
D3D12_RESOURCE_STATES InitialResourceState,
1333
const D3D12_CLEAR_VALUE *pOptimizedClearValue,
1334
REFIID riidResource,
1335
void** ppvResource);
1336
1337
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
1338
/** \brief Similar to Allocator::CreateAliasingResource, but supports new structure `D3D12_RESOURCE_DESC1`.
1339
1340
It internally uses `ID3D12Device8::CreatePlacedResource1`.
1341
1342
To work correctly, `ID3D12Device8` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
1343
*/
1344
HRESULT CreateAliasingResource1(Allocation* pAllocation,
1345
UINT64 AllocationLocalOffset,
1346
const D3D12_RESOURCE_DESC1* pResourceDesc,
1347
D3D12_RESOURCE_STATES InitialResourceState,
1348
const D3D12_CLEAR_VALUE* pOptimizedClearValue,
1349
REFIID riidResource,
1350
void** ppvResource);
1351
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
1352
1353
#ifdef __ID3D12Device10_INTERFACE_DEFINED__
1354
/** \brief Similar to Allocator::CreateAliasingResource1, but there are initial layout instead of state and
1355
castable formats list
1356
1357
It internally uses `ID3D12Device10::CreatePlacedResource2`.
1358
1359
To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
1360
*/
1361
HRESULT CreateAliasingResource2(Allocation* pAllocation,
1362
UINT64 AllocationLocalOffset,
1363
const D3D12_RESOURCE_DESC1* pResourceDesc,
1364
D3D12_BARRIER_LAYOUT InitialLayout,
1365
const D3D12_CLEAR_VALUE* pOptimizedClearValue,
1366
UINT32 NumCastableFormats,
1367
DXGI_FORMAT* pCastableFormats,
1368
REFIID riidResource,
1369
void** ppvResource);
1370
#endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
1371
1372
/** \brief Creates custom pool.
1373
*/
1374
HRESULT CreatePool(
1375
const POOL_DESC* pPoolDesc,
1376
Pool** ppPool);
1377
1378
/** \brief Sets the index of the current frame.
1379
1380
This function is used to set the frame index in the allocator when a new game frame begins.
1381
*/
1382
void SetCurrentFrameIndex(UINT frameIndex);
1383
1384
/** \brief Retrieves information about current memory usage and budget.
1385
1386
\param[out] pLocalBudget Optional, can be null.
1387
\param[out] pNonLocalBudget Optional, can be null.
1388
1389
- When IsUMA() `== FALSE` (discrete graphics card):
1390
- `pLocalBudget` returns the budget of the video memory.
1391
- `pNonLocalBudget` returns the budget of the system memory available for D3D12 resources.
1392
- When IsUMA() `== TRUE` (integrated graphics chip):
1393
- `pLocalBudget` returns the budget of the shared memory available for all D3D12 resources.
1394
All memory is considered "local".
1395
- `pNonLocalBudget` is not applicable and returns zeros.
1396
1397
This function is called "get" not "calculate" because it is very fast, suitable to be called
1398
every frame or every allocation. For more detailed statistics use CalculateStatistics().
1399
1400
Note that when using allocator from multiple threads, returned information may immediately
1401
become outdated.
1402
*/
1403
void GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget);
1404
1405
/** \brief Retrieves statistics from current state of the allocator.
1406
1407
This function is called "calculate" not "get" because it has to traverse all
1408
internal data structures, so it may be quite slow. Use it for debugging purposes.
1409
For faster but more brief statistics suitable to be called every frame or every allocation,
1410
use GetBudget().
1411
1412
Note that when using allocator from multiple threads, returned information may immediately
1413
become outdated.
1414
*/
1415
void CalculateStatistics(TotalStatistics* pStats);
1416
1417
/** \brief Builds and returns statistics as a string in JSON format.
1418
*
1419
@param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
1420
@param DetailedMap `TRUE` to include full list of allocations (can make the string quite long), `FALSE` to only return statistics.
1421
*/
1422
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const;
1423
1424
/// Frees memory of a string returned from Allocator::BuildStatsString.
1425
void FreeStatsString(WCHAR* pStatsString) const;
1426
1427
/** \brief Begins defragmentation process of the default pools.
1428
1429
\param pDesc Structure filled with parameters of defragmentation.
1430
\param[out] ppContext Context object that will manage defragmentation.
1431
1432
For more information about defragmentation, see documentation chapter:
1433
[Defragmentation](@ref defragmentation).
1434
*/
1435
void BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext);
1436
1437
protected:
1438
void ReleaseThis() override;
1439
1440
private:
1441
friend D3D12MA_API HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);
1442
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
1443
friend class DefragmentationContext;
1444
friend class Pool;
1445
1446
Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
1447
~Allocator();
1448
1449
AllocatorPimpl* m_Pimpl;
1450
1451
D3D12MA_CLASS_NO_COPY(Allocator)
1452
};
1453
1454
1455
/// \brief Bit flags to be used with VIRTUAL_BLOCK_DESC::Flags.
1456
enum VIRTUAL_BLOCK_FLAGS
1457
{
1458
/// Zero
1459
VIRTUAL_BLOCK_FLAG_NONE = 0,
1460
1461
/** \brief Enables alternative, linear allocation algorithm in this virtual block.
1462
1463
Specify this flag to enable linear allocation algorithm, which always creates
1464
new allocations after last one and doesn't reuse space from allocations freed in
1465
between. It trades memory consumption for simplified algorithm and data
1466
structure, which has better performance and uses less memory for metadata.
1467
1468
By using this flag, you can achieve behavior of free-at-once, stack,
1469
ring buffer, and double stack.
1470
For details, see documentation chapter \ref linear_algorithm.
1471
*/
1472
VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR = POOL_FLAG_ALGORITHM_LINEAR,
1473
1474
// Bit mask to extract only `ALGORITHM` bits from entire set of flags.
1475
VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_MASK
1476
};
1477
1478
/// Parameters of created D3D12MA::VirtualBlock object to be passed to CreateVirtualBlock().
1479
struct VIRTUAL_BLOCK_DESC
1480
{
1481
/// Flags.
1482
VIRTUAL_BLOCK_FLAGS Flags;
1483
/** \brief Total size of the block.
1484
1485
Sizes can be expressed in bytes or any units you want as long as you are consistent in using them.
1486
For example, if you allocate from some array of structures, 1 can mean single instance of entire structure.
1487
*/
1488
UINT64 Size;
1489
/** \brief Custom CPU memory allocation callbacks. Optional.
1490
1491
Optional, can be null. When specified, will be used for all CPU-side memory allocations.
1492
*/
1493
const ALLOCATION_CALLBACKS* pAllocationCallbacks;
1494
};
1495
1496
/// \brief Bit flags to be used with VIRTUAL_ALLOCATION_DESC::Flags.
1497
enum VIRTUAL_ALLOCATION_FLAGS
1498
{
1499
/// Zero
1500
VIRTUAL_ALLOCATION_FLAG_NONE = 0,
1501
1502
/** \brief Allocation will be created from upper stack in a double stack pool.
1503
1504
This flag is only allowed for virtual blocks created with #VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR flag.
1505
*/
1506
VIRTUAL_ALLOCATION_FLAG_UPPER_ADDRESS = ALLOCATION_FLAG_UPPER_ADDRESS,
1507
1508
/// %Allocation strategy that tries to minimize memory usage.
1509
VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_MEMORY = ALLOCATION_FLAG_STRATEGY_MIN_MEMORY,
1510
/// %Allocation strategy that tries to minimize allocation time.
1511
VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_TIME = ALLOCATION_FLAG_STRATEGY_MIN_TIME,
1512
/** %Allocation strategy that chooses always the lowest offset in available space.
1513
This is not the most efficient strategy but achieves highly packed data.
1514
*/
1515
VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_OFFSET = ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
1516
/** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags.
1517
1518
These strategy flags are binary compatible with equivalent flags in #ALLOCATION_FLAGS.
1519
*/
1520
VIRTUAL_ALLOCATION_FLAG_STRATEGY_MASK = ALLOCATION_FLAG_STRATEGY_MASK,
1521
};
1522
1523
/// Parameters of created virtual allocation to be passed to VirtualBlock::Allocate().
1524
struct VIRTUAL_ALLOCATION_DESC
1525
{
1526
/// Flags for the virtual allocation.
1527
VIRTUAL_ALLOCATION_FLAGS Flags;
1528
/** \brief Size of the allocation.
1529
1530
Cannot be zero.
1531
*/
1532
UINT64 Size;
1533
/** \brief Required alignment of the allocation.
1534
1535
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.
1536
*/
1537
UINT64 Alignment;
1538
/** \brief Custom pointer to be associated with the allocation.
1539
1540
It can be fetched or changed later.
1541
*/
1542
void* pPrivateData;
1543
};
1544
1545
/// Parameters of an existing virtual allocation, returned by VirtualBlock::GetAllocationInfo().
1546
struct VIRTUAL_ALLOCATION_INFO
1547
{
1548
/// \brief Offset of the allocation.
1549
UINT64 Offset;
1550
/** \brief Size of the allocation.
1551
1552
Same value as passed in VIRTUAL_ALLOCATION_DESC::Size.
1553
*/
1554
UINT64 Size;
1555
/** \brief Custom pointer associated with the allocation.
1556
1557
Same value as passed in VIRTUAL_ALLOCATION_DESC::pPrivateData or VirtualBlock::SetAllocationPrivateData().
1558
*/
1559
void* pPrivateData;
1560
};
1561
1562
/** \brief Represents pure allocation algorithm and a data structure with allocations in some memory block, without actually allocating any GPU memory.
1563
1564
This class allows to use the core algorithm of the library custom allocations e.g. CPU memory or
1565
sub-allocation regions inside a single GPU buffer.
1566
1567
To create this object, fill in D3D12MA::VIRTUAL_BLOCK_DESC and call CreateVirtualBlock().
1568
To destroy it, call its method `VirtualBlock::Release()`.
1569
You need to free all the allocations within this block or call Clear() before destroying it.
1570
1571
This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally.
1572
*/
1573
class D3D12MA_API VirtualBlock : public IUnknownImpl
1574
{
1575
public:
1576
/** \brief Returns true if the block is empty - contains 0 allocations.
1577
*/
1578
BOOL IsEmpty() const;
1579
/** \brief Returns information about an allocation - its offset, size and custom pointer.
1580
*/
1581
void GetAllocationInfo(VirtualAllocation allocation, VIRTUAL_ALLOCATION_INFO* pInfo) const;
1582
1583
/** \brief Creates new allocation.
1584
\param pDesc
1585
\param[out] pAllocation Unique indentifier of the new allocation within single block.
1586
\param[out] pOffset Returned offset of the new allocation. Optional, can be null.
1587
\return `S_OK` if allocation succeeded, `E_OUTOFMEMORY` if it failed.
1588
1589
If the allocation failed, `pAllocation->AllocHandle` is set to 0 and `pOffset`, if not null, is set to `UINT64_MAX`.
1590
*/
1591
HRESULT Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, VirtualAllocation* pAllocation, UINT64* pOffset);
1592
/** \brief Frees the allocation.
1593
1594
Calling this function with `allocation.AllocHandle == 0` is correct and does nothing.
1595
*/
1596
void FreeAllocation(VirtualAllocation allocation);
1597
/** \brief Frees all the allocations.
1598
*/
1599
void Clear();
1600
/** \brief Changes custom pointer for an allocation to a new value.
1601
*/
1602
void SetAllocationPrivateData(VirtualAllocation allocation, void* pPrivateData);
1603
/** \brief Retrieves basic statistics of the virtual block that are fast to calculate.
1604
1605
\param[out] pStats %Statistics of the virtual block.
1606
*/
1607
void GetStatistics(Statistics* pStats) const;
1608
/** \brief Retrieves detailed statistics of the virtual block that are slower to calculate.
1609
1610
\param[out] pStats %Statistics of the virtual block.
1611
*/
1612
void CalculateStatistics(DetailedStatistics* pStats) const;
1613
1614
/** \brief Builds and returns statistics as a string in JSON format, including the list of allocations with their parameters.
1615
@param[out] ppStatsString Must be freed using VirtualBlock::FreeStatsString.
1616
*/
1617
void BuildStatsString(WCHAR** ppStatsString) const;
1618
1619
/** \brief Frees memory of a string returned from VirtualBlock::BuildStatsString.
1620
*/
1621
void FreeStatsString(WCHAR* pStatsString) const;
1622
1623
protected:
1624
void ReleaseThis() override;
1625
1626
private:
1627
friend D3D12MA_API HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC*, VirtualBlock**);
1628
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
1629
1630
VirtualBlockPimpl* m_Pimpl;
1631
1632
VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
1633
~VirtualBlock();
1634
1635
D3D12MA_CLASS_NO_COPY(VirtualBlock)
1636
};
1637
1638
1639
/** \brief Creates new main D3D12MA::Allocator object and returns it through `ppAllocator`.
1640
1641
You normally only need to call it once and keep a single Allocator object for your `ID3D12Device`.
1642
*/
1643
D3D12MA_API HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator);
1644
1645
/** \brief Creates new D3D12MA::VirtualBlock object and returns it through `ppVirtualBlock`.
1646
1647
Note you don't need to create D3D12MA::Allocator to use virtual blocks.
1648
*/
1649
D3D12MA_API HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock);
1650
1651
#ifndef D3D12MA_NO_HELPERS
1652
1653
/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::ALLOCATION_DESC structure.
1654
*/
1655
struct CALLOCATION_DESC : public ALLOCATION_DESC
1656
{
1657
/// Default constructor. Leaves the structure uninitialized.
1658
CALLOCATION_DESC() = default;
1659
/// Constructor initializing from the base D3D12MA::ALLOCATION_DESC structure.
1660
explicit CALLOCATION_DESC(const ALLOCATION_DESC& o) noexcept
1661
: ALLOCATION_DESC(o)
1662
{
1663
}
1664
/// Constructor initializing description of an allocation to be created in a specific custom pool.
1665
explicit CALLOCATION_DESC(Pool* customPool,
1666
ALLOCATION_FLAGS flags = ALLOCATION_FLAG_NONE,
1667
void* privateData = NULL) noexcept
1668
{
1669
Flags = flags;
1670
HeapType = (D3D12_HEAP_TYPE)0;
1671
ExtraHeapFlags = D3D12_HEAP_FLAG_NONE;
1672
CustomPool = customPool;
1673
pPrivateData = privateData;
1674
}
1675
/// Constructor initializing description of an allocation to be created in a default pool of a specific `D3D12_HEAP_TYPE`.
1676
explicit CALLOCATION_DESC(D3D12_HEAP_TYPE heapType,
1677
ALLOCATION_FLAGS flags = ALLOCATION_FLAG_NONE,
1678
void* privateData = NULL,
1679
D3D12_HEAP_FLAGS extraHeapFlags = D3D12MA_RECOMMENDED_HEAP_FLAGS) noexcept
1680
{
1681
Flags = flags;
1682
HeapType = heapType;
1683
ExtraHeapFlags = extraHeapFlags;
1684
CustomPool = NULL;
1685
pPrivateData = privateData;
1686
}
1687
};
1688
1689
/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::POOL_DESC structure.
1690
*/
1691
struct CPOOL_DESC : public POOL_DESC
1692
{
1693
/// Default constructor. Leaves the structure uninitialized.
1694
CPOOL_DESC() = default;
1695
/// Constructor initializing from the base D3D12MA::POOL_DESC structure.
1696
explicit CPOOL_DESC(const POOL_DESC& o) noexcept
1697
: POOL_DESC(o)
1698
{
1699
}
1700
/// Constructor initializing description of a custom pool created in one of the standard `D3D12_HEAP_TYPE`.
1701
explicit CPOOL_DESC(D3D12_HEAP_TYPE heapType,
1702
D3D12_HEAP_FLAGS heapFlags,
1703
POOL_FLAGS flags = D3D12MA_RECOMMENDED_POOL_FLAGS,
1704
UINT64 blockSize = 0,
1705
UINT minBlockCount = 0,
1706
UINT maxBlockCount = UINT_MAX,
1707
D3D12_RESIDENCY_PRIORITY residencyPriority = D3D12_RESIDENCY_PRIORITY_NORMAL) noexcept
1708
{
1709
Flags = flags;
1710
HeapProperties = {};
1711
HeapProperties.Type = heapType;
1712
HeapFlags = heapFlags;
1713
BlockSize = blockSize;
1714
MinBlockCount = minBlockCount;
1715
MaxBlockCount = maxBlockCount;
1716
MinAllocationAlignment = 0;
1717
pProtectedSession = NULL;
1718
ResidencyPriority = residencyPriority;
1719
}
1720
/// Constructor initializing description of a custom pool created with custom `D3D12_HEAP_PROPERTIES`.
1721
explicit CPOOL_DESC(const D3D12_HEAP_PROPERTIES heapProperties,
1722
D3D12_HEAP_FLAGS heapFlags,
1723
POOL_FLAGS flags = D3D12MA_RECOMMENDED_POOL_FLAGS,
1724
UINT64 blockSize = 0,
1725
UINT minBlockCount = 0,
1726
UINT maxBlockCount = UINT_MAX,
1727
D3D12_RESIDENCY_PRIORITY residencyPriority = D3D12_RESIDENCY_PRIORITY_NORMAL) noexcept
1728
{
1729
Flags = flags;
1730
HeapProperties = heapProperties;
1731
HeapFlags = heapFlags;
1732
BlockSize = blockSize;
1733
MinBlockCount = minBlockCount;
1734
MaxBlockCount = maxBlockCount;
1735
MinAllocationAlignment = 0;
1736
pProtectedSession = NULL;
1737
ResidencyPriority = residencyPriority;
1738
}
1739
};
1740
1741
/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::VIRTUAL_BLOCK_DESC structure.
1742
*/
1743
struct CVIRTUAL_BLOCK_DESC : public VIRTUAL_BLOCK_DESC
1744
{
1745
/// Default constructor. Leaves the structure uninitialized.
1746
CVIRTUAL_BLOCK_DESC() = default;
1747
/// Constructor initializing from the base D3D12MA::VIRTUAL_BLOCK_DESC structure.
1748
explicit CVIRTUAL_BLOCK_DESC(const VIRTUAL_BLOCK_DESC& o) noexcept
1749
: VIRTUAL_BLOCK_DESC(o)
1750
{
1751
}
1752
/// Constructor initializing description of a virtual block with given parameters.
1753
explicit CVIRTUAL_BLOCK_DESC(UINT64 size,
1754
VIRTUAL_BLOCK_FLAGS flags = VIRTUAL_BLOCK_FLAG_NONE,
1755
const ALLOCATION_CALLBACKS* allocationCallbacks = NULL) noexcept
1756
{
1757
Flags = flags;
1758
Size = size;
1759
pAllocationCallbacks = allocationCallbacks;
1760
}
1761
};
1762
1763
/** \brief Helper structure that helps with complete and conscise initialization of the D3D12MA::VIRTUAL_ALLOCATION_DESC structure.
1764
*/
1765
struct CVIRTUAL_ALLOCATION_DESC : public VIRTUAL_ALLOCATION_DESC
1766
{
1767
/// Default constructor. Leaves the structure uninitialized.
1768
CVIRTUAL_ALLOCATION_DESC() = default;
1769
/// Constructor initializing from the base D3D12MA::VIRTUAL_ALLOCATION_DESC structure.
1770
explicit CVIRTUAL_ALLOCATION_DESC(const VIRTUAL_ALLOCATION_DESC& o) noexcept
1771
: VIRTUAL_ALLOCATION_DESC(o)
1772
{
1773
}
1774
/// Constructor initializing description of a virtual allocation with given parameters.
1775
explicit CVIRTUAL_ALLOCATION_DESC(UINT64 size, UINT64 alignment,
1776
VIRTUAL_ALLOCATION_FLAGS flags = VIRTUAL_ALLOCATION_FLAG_NONE,
1777
void* privateData = NULL) noexcept
1778
{
1779
Flags = flags;
1780
Size = size;
1781
Alignment = alignment;
1782
pPrivateData = privateData;
1783
}
1784
};
1785
1786
#endif // #ifndef D3D12MA_NO_HELPERS
1787
1788
} // namespace D3D12MA
1789
1790
/// \cond INTERNAL
1791
DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATION_FLAGS);
1792
DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::DEFRAGMENTATION_FLAGS);
1793
DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATOR_FLAGS);
1794
DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::POOL_FLAGS);
1795
DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_BLOCK_FLAGS);
1796
DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_ALLOCATION_FLAGS);
1797
/// \endcond
1798
1799
/**
1800
\page quick_start Quick start
1801
1802
\section quick_start_project_setup Project setup and initialization
1803
1804
This is a small, standalone C++ library. It consists of 2 files:
1805
"D3D12MemAlloc.h" header file with public interface and "D3D12MemAlloc.cpp" with
1806
internal implementation. The only external dependencies are WinAPI, Direct3D 12,
1807
and parts of C/C++ standard library (but STL containers, exceptions, or RTTI are
1808
not used).
1809
1810
The library is developed and tested using Microsoft Visual Studio 2022, but it
1811
should work with other compilers as well. It is designed for 64-bit code.
1812
1813
To use the library in your project:
1814
1815
(1.) Copy files `D3D12MemAlloc.cpp`, `%D3D12MemAlloc.h` to your project.
1816
1817
(2.) Make `D3D12MemAlloc.cpp` compiling as part of the project, as C++ code.
1818
1819
(3.) Include library header in each CPP file that needs to use the library.
1820
1821
\code
1822
#include "D3D12MemAlloc.h"
1823
\endcode
1824
1825
(4.) Right after you created `ID3D12Device`, fill D3D12MA::ALLOCATOR_DESC
1826
structure and call function D3D12MA::CreateAllocator to create the main
1827
D3D12MA::Allocator object.
1828
1829
Please note that all symbols of the library are declared inside #D3D12MA namespace.
1830
1831
\code
1832
IDXGIAdapter* adapter = ...
1833
ID3D12Device* device = ...
1834
1835
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
1836
allocatorDesc.pDevice = device;
1837
allocatorDesc.pAdapter = adapter;
1838
allocatorDesc.Flags = D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS;
1839
1840
D3D12MA::Allocator* allocator;
1841
HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
1842
// Check hr...
1843
\endcode
1844
1845
(5.) Right before destroying the D3D12 device, destroy the allocator object.
1846
1847
\code
1848
allocator->Release();
1849
\endcode
1850
1851
Objects of this library must be destroyed by calling `Release` method.
1852
They are somewhat compatible with COM: they implement `IUnknown` interface with its virtual methods: `AddRef`, `Release`, `QueryInterface`,
1853
and they are reference-counted internally.
1854
You can use smart pointers designed for COM with objects of this library - e.g. `CComPtr` or `Microsoft::WRL::ComPtr`.
1855
The reference counter is thread-safe.
1856
`QueryInterface` method supports only `IUnknown`, as classes of this library don't define their own GUIDs.
1857
1858
1859
\section quick_start_creating_resources Creating resources
1860
1861
To use the library for creating resources (textures and buffers), call method
1862
D3D12MA::Allocator::CreateResource in the place where you would previously call
1863
`ID3D12Device::CreateCommittedResource`.
1864
1865
The function has similar syntax, but it expects structure D3D12MA::ALLOCATION_DESC
1866
to be passed along with `D3D12_RESOURCE_DESC` and other parameters for created
1867
resource. This structure describes parameters of the desired memory allocation,
1868
including choice of `D3D12_HEAP_TYPE`.
1869
1870
The function returns a new object of type D3D12MA::Allocation.
1871
It represents allocated memory and can be queried for size, offset, `ID3D12Heap`.
1872
It also holds a reference to the `ID3D12Resource`, which can be accessed by calling D3D12MA::Allocation::GetResource().
1873
1874
\code
1875
D3D12_RESOURCE_DESC resourceDesc = {};
1876
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1877
resourceDesc.Alignment = 0;
1878
resourceDesc.Width = 1024;
1879
resourceDesc.Height = 1024;
1880
resourceDesc.DepthOrArraySize = 1;
1881
resourceDesc.MipLevels = 1;
1882
resourceDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1883
resourceDesc.SampleDesc.Count = 1;
1884
resourceDesc.SampleDesc.Quality = 0;
1885
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
1886
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
1887
1888
D3D12MA::ALLOCATION_DESC allocationDesc = {};
1889
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
1890
1891
D3D12MA::Allocation* allocation;
1892
HRESULT hr = allocator->CreateResource(
1893
&allocationDesc,
1894
&resourceDesc,
1895
D3D12_RESOURCE_STATE_COPY_DEST,
1896
NULL,
1897
&allocation,
1898
IID_NULL, NULL);
1899
// Check hr...
1900
1901
ID3D12Resource* res = allocation->GetResource();
1902
// Use res...
1903
\endcode
1904
1905
You need to release the allocation object when no longer needed.
1906
This will also release the D3D12 resource.
1907
1908
\code
1909
allocation->Release();
1910
\endcode
1911
1912
The advantage of using the allocator instead of creating committed resource, and
1913
the main purpose of this library, is that it can decide to allocate bigger memory
1914
heap internally using `ID3D12Device::CreateHeap` and place multiple resources in
1915
it, at different offsets, using `ID3D12Device::CreatePlacedResource`. The library
1916
manages its own collection of allocated memory blocks (heaps) and remembers which
1917
parts of them are occupied and which parts are free to be used for new resources.
1918
1919
It is important to remember that resources created as placed don't have their memory
1920
initialized to zeros, but may contain garbage data, so they need to be fully initialized
1921
before usage, e.g. using Clear (`ClearRenderTargetView`), Discard (`DiscardResource`),
1922
or Copy (`CopyResource`).
1923
1924
The library also automatically handles resource heap tier.
1925
When `D3D12_FEATURE_DATA_D3D12_OPTIONS::ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1`,
1926
resources of 3 types: buffers, textures that are render targets or depth-stencil,
1927
and other textures must be kept in separate heaps. When `D3D12_RESOURCE_HEAP_TIER_2`,
1928
they can be kept together. By using this library, you don't need to handle this
1929
manually.
1930
1931
1932
\section quick_start_resource_reference_counting Resource reference counting
1933
1934
`ID3D12Resource` and other interfaces of Direct3D 12 use COM, so they are reference-counted.
1935
Objects of this library are reference-counted as well.
1936
An object of type D3D12MA::Allocation remembers the resource (buffer or texture)
1937
that was created together with this memory allocation
1938
and holds a reference to the `ID3D12Resource` object.
1939
(Note this is a difference to Vulkan Memory Allocator, where a `VmaAllocation` object has no connection
1940
with the buffer or image that was created with it.)
1941
Thus, it is important to manage the resource reference counter properly.
1942
1943
<b>The simplest use case</b> is shown in the code snippet above.
1944
When only D3D12MA::Allocation object is obtained from a function call like D3D12MA::Allocator::CreateResource,
1945
it remembers the `ID3D12Resource` that was created with it and holds a reference to it.
1946
The resource can be obtained by calling `allocation->GetResource()`, which doesn't increment the resource
1947
reference counter.
1948
Calling `allocation->Release()` will decrease the resource reference counter, which is 1 in this case,
1949
so the resource will be released.
1950
1951
<b>Second option</b> is to retrieve a pointer to the resource along with D3D12MA::Allocation.
1952
Last parameters of the resource creation function can be used for this purpose.
1953
1954
\code
1955
D3D12MA::Allocation* allocation;
1956
ID3D12Resource* resource;
1957
HRESULT hr = allocator->CreateResource(
1958
&allocationDesc,
1959
&resourceDesc,
1960
D3D12_RESOURCE_STATE_COPY_DEST,
1961
NULL,
1962
&allocation,
1963
IID_PPV_ARGS(&resource));
1964
1965
// Use resource...
1966
\endcode
1967
1968
In this case, returned pointer `resource` is equal to `allocation->GetResource()`,
1969
but the creation function additionally increases resource reference counter for the purpose of returning it from this call
1970
(it actually calls `QueryInterface` internally), so the resource will have the counter = 2.
1971
The resource then need to be released along with the allocation, in this particular order,
1972
to make sure the resource is destroyed before its memory heap can potentially be freed.
1973
1974
\code
1975
resource->Release();
1976
allocation->Release();
1977
\endcode
1978
1979
<b>More advanced use cases</b> are possible when we consider that an D3D12MA::Allocation object can just hold
1980
a reference to any resource.
1981
It can be changed by calling D3D12MA::Allocation::SetResource. This function
1982
releases the old resource and calls `AddRef` on the new one.
1983
1984
Special care must be taken when performing <b>defragmentation</b>.
1985
The new resource created at the destination place should be set as `pass.pMoves[i].pDstTmpAllocation->SetResource(newRes)`,
1986
but it is moved to the source allocation at end of the defragmentation pass,
1987
while the old resource accessible through `pass.pMoves[i].pSrcAllocation->GetResource()` is then released.
1988
For more information, see documentation chapter \ref defragmentation.
1989
1990
1991
\section quick_start_mapping_memory Mapping memory
1992
1993
The process of getting regular CPU-side pointer to the memory of a resource in
1994
Direct3D is called "mapping". There are rules and restrictions to this process,
1995
as described in D3D12 documentation of `ID3D12Resource::Map` method.
1996
1997
Mapping happens on the level of particular resources, not entire memory heaps,
1998
and so it is out of scope of this library. Just as the documentation of the `Map` function says:
1999
2000
- Returned pointer refers to data of particular subresource, not entire memory heap.
2001
- You can map same resource multiple times. It is ref-counted internally.
2002
- Mapping is thread-safe.
2003
- Unmapping is not required before resource destruction.
2004
- Unmapping may not be required before using written data - some heap types on
2005
some platforms support resources persistently mapped.
2006
2007
When using this library, you can map and use your resources normally without
2008
considering whether they are created as committed resources or placed resources in one large heap.
2009
2010
Example for buffer created and filled in `UPLOAD` heap type:
2011
2012
\code
2013
const UINT64 bufSize = 65536;
2014
const float* bufData = ...;
2015
2016
D3D12_RESOURCE_DESC resourceDesc = {};
2017
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2018
resourceDesc.Alignment = 0;
2019
resourceDesc.Width = bufSize;
2020
resourceDesc.Height = 1;
2021
resourceDesc.DepthOrArraySize = 1;
2022
resourceDesc.MipLevels = 1;
2023
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2024
resourceDesc.SampleDesc.Count = 1;
2025
resourceDesc.SampleDesc.Quality = 0;
2026
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2027
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2028
2029
D3D12MA::ALLOCATION_DESC allocationDesc = {};
2030
allocationDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
2031
2032
D3D12Resource* resource;
2033
D3D12MA::Allocation* allocation;
2034
HRESULT hr = allocator->CreateResource(
2035
&allocationDesc,
2036
&resourceDesc,
2037
D3D12_RESOURCE_STATE_GENERIC_READ,
2038
NULL,
2039
&allocation,
2040
IID_PPV_ARGS(&resource));
2041
2042
D3D12_RANGE emptyRange = {0, 0};
2043
void* mappedPtr;
2044
hr = resource->Map(0, &emptyRange, &mappedPtr);
2045
2046
memcpy(mappedPtr, bufData, bufSize);
2047
2048
resource->Unmap(0, NULL);
2049
\endcode
2050
2051
2052
\section quick_start_helper_structures Helper structures
2053
2054
DirectX 12 Agility SDK offers a library of helpers in files "build\native\include\d3dx12\*.h".
2055
They include structures that help with complete and concise initialization of the core D3D12 `*_DESC` structures
2056
by using some basic C++ features (constructors, static methods, default parameters).
2057
They inherit from these structures, so they support implicit casting to them.
2058
For example, structure `CD3DX12_RESOURCE_DESC` can be used to conveniently fill in structure `D3D12_RESOURCE_DESC`.
2059
2060
Similarly, this library provides a set of helper structures that aid in initialization of some of the `*_DESC` structures defined in the library.
2061
These are:
2062
2063
- D3D12MA::CALLOCATION_DESC, which inherits from D3D12MA::ALLOCATION_DESC.
2064
- D3D12MA::CPOOL_DESC, which inherits from D3D12MA::POOL_DESC.
2065
- D3D12MA::CVIRTUAL_BLOCK_DESC, which inherits from D3D12MA::VIRTUAL_BLOCK_DESC.
2066
- D3D12MA::CVIRTUAL_ALLOCATION_DESC, which inherits from D3D12MA::VIRTUAL_ALLOCATION_DESC.
2067
2068
For example, when you want to create a buffer in the `UPLAOD` heap using minimal allocation time, you can use base structures:
2069
2070
\code
2071
D3D12MA::ALLOCATION_DESC allocDesc;
2072
allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME;
2073
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
2074
allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_NONE;
2075
allocDesc.CustomPool = NULL;
2076
allocDesc.pPrivateData = NULL;
2077
2078
D3D12_RESOURCE_DESC resDesc;
2079
resDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2080
resDesc.Alignment = 0;
2081
resDesc.Width = myBufSize;
2082
resDesc.Height = 1;
2083
resDesc.DepthOrArraySize = 1;
2084
resDesc.MipLevels = 1;
2085
resDesc.Format = DXGI_FORMAT_UNKNOWN;
2086
resDesc.SampleDesc.Count = 1;
2087
resDesc.SampleDesc.Quality = 0;
2088
resDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2089
resDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2090
2091
D3D12MA::Allocation* alloc;
2092
ID3D12Resource* res;
2093
HRESULT hr = allocator->CreateResource(&allocDesc, &resDesc,
2094
D3D12_RESOURCE_STATE_COMMON, NULL, &alloc, IID_PPV_ARGS(&res));
2095
// Check hr...
2096
\endcode
2097
2098
Or you can use helper structs from both D3X12 library and this library to make the code shorter:
2099
2100
\code
2101
D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{
2102
D3D12_HEAP_TYPE_UPLOAD,
2103
D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME };
2104
2105
CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(myBufSize);
2106
2107
D3D12MA::Allocation* alloc;
2108
ID3D12Resource* res;
2109
HRESULT hr = allocator->CreateResource(&allocDesc, &resDesc,
2110
D3D12_RESOURCE_STATE_COMMON, NULL, &alloc, IID_PPV_ARGS(&res));
2111
// Check hr...
2112
\endcode
2113
2114
\page custom_pools Custom memory pools
2115
2116
A "pool" is a collection of memory blocks that share certain properties.
2117
Allocator creates 3 default pools: for `D3D12_HEAP_TYPE_DEFAULT`, `UPLOAD`, `READBACK`.
2118
A default pool automatically grows in size. Size of allocated blocks is also variable and managed automatically.
2119
Typical allocations are created in these pools. You can also create custom pools.
2120
2121
\section custom_pools_usage Usage
2122
2123
To create a custom pool, fill in structure D3D12MA::POOL_DESC and call function D3D12MA::Allocator::CreatePool
2124
to obtain object D3D12MA::Pool. Example:
2125
2126
\code
2127
POOL_DESC poolDesc = {};
2128
poolDesc.HeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
2129
poolDesc.Flags = D3D12MA_RECOMMENDED_POOL_FLAGS;
2130
poolDesc.HeapFlags = D3D12MA_RECOMMENDED_HEAP_FLAGS | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
2131
2132
Pool* pool;
2133
HRESULT hr = allocator->CreatePool(&poolDesc, &pool);
2134
\endcode
2135
2136
To allocate resources out of a custom pool, only set member D3D12MA::ALLOCATION_DESC::CustomPool.
2137
Example:
2138
2139
\code
2140
ALLOCATION_DESC allocDesc = {};
2141
allocDesc.CustomPool = pool;
2142
2143
D3D12_RESOURCE_DESC resDesc = ...
2144
Allocation* alloc;
2145
hr = allocator->CreateResource(&allocDesc, &resDesc,
2146
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &alloc, IID_NULL, NULL);
2147
\endcode
2148
2149
All allocations must be released before releasing the pool.
2150
The pool must be released before relasing the allocator.
2151
2152
\code
2153
alloc->Release();
2154
pool->Release();
2155
\endcode
2156
2157
\section custom_pools_features_and_benefits Features and benefits
2158
2159
While it is recommended to use default pools whenever possible for simplicity and to give the allocator
2160
more opportunities for internal optimizations, custom pools may be useful in following cases:
2161
2162
- To keep some resources separate from others in memory.
2163
- To keep track of memory usage of just a specific group of resources. %Statistics can be queried using
2164
D3D12MA::Pool::CalculateStatistics.
2165
- To use specific size of a memory block (`ID3D12Heap`). To set it, use member D3D12MA::POOL_DESC::BlockSize.
2166
When set to 0, the library uses automatically determined, variable block sizes.
2167
- To reserve some minimum amount of memory allocated. To use it, set member D3D12MA::POOL_DESC::MinBlockCount.
2168
- To limit maximum amount of memory allocated. To use it, set member D3D12MA::POOL_DESC::MaxBlockCount.
2169
- To use extended parameters of the D3D12 memory allocation. While resources created from default pools
2170
can only specify `D3D12_HEAP_TYPE_DEFAULT`, `UPLOAD`, `READBACK`, a custom pool may use non-standard
2171
`D3D12_HEAP_PROPERTIES` (member D3D12MA::POOL_DESC::HeapProperties) and `D3D12_HEAP_FLAGS`
2172
(D3D12MA::POOL_DESC::HeapFlags), which is useful e.g. for cross-adapter sharing or UMA
2173
(see also D3D12MA::Allocator::IsUMA).
2174
2175
New versions of this library support creating **committed allocations in custom pools**.
2176
It is supported only when D3D12MA::POOL_DESC::BlockSize = 0.
2177
To use this feature, set D3D12MA::ALLOCATION_DESC::CustomPool to the pointer to your custom pool and
2178
D3D12MA::ALLOCATION_DESC::Flags to D3D12MA::ALLOCATION_FLAG_COMMITTED. Example:
2179
2180
\code
2181
ALLOCATION_DESC allocDesc = {};
2182
allocDesc.CustomPool = pool;
2183
allocDesc.Flags = ALLOCATION_FLAG_COMMITTED;
2184
2185
D3D12_RESOURCE_DESC resDesc = ...
2186
Allocation* alloc;
2187
ID3D12Resource* res;
2188
hr = allocator->CreateResource(&allocDesc, &resDesc,
2189
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &alloc, IID_PPV_ARGS(&res));
2190
\endcode
2191
2192
This feature may seem unnecessary, but creating committed allocations from custom pools may be useful
2193
in some cases, e.g. to have separate memory usage statistics for some group of resources or to use
2194
extended allocation parameters, like custom `D3D12_HEAP_PROPERTIES`, which are available only in custom pools.
2195
2196
2197
\page optimal_allocation Optimal resource allocation
2198
2199
This library tries to automatically make optimal choices for the resources you create,
2200
so you don't need to care about them.
2201
There are some advanced features of Direct3D 12 that you may use to optimize your memory management.
2202
There are also some settings in %D3D12MA that you may change to alter its default behavior.
2203
This page provides miscellaneous advice about features of D3D12 and %D3D12MA that are
2204
non-essential, but may improve the stability or performance of your app.
2205
2206
\section optimal_allocation_avoiding_running_out_of_memory Avoiding running out of memory
2207
2208
When trying to allocate more memory than available in the current heap
2209
(e.g., video memory on the graphics card, system memory), one of few bad things can happen:
2210
2211
- The allocation (resource creation) function call can fail with `HRESULT` value other than `S_OK`.
2212
- The allocation may succeed, but take long time (even a significant fraction of a second).
2213
- Some resources are automatically demoted from video memory to system memory, degrading the app performance.
2214
- Even a crash of the entire graphics driver can happen, resulting in the D3D12 "device removal", which is usually
2215
catastrophic for the application.
2216
2217
Unfortunately, there is no way to be 100% protected against memory overcommitment.
2218
The best approach is to avoid allocating too much memory.
2219
2220
The full capacity of the memory can be queried using function D3D12MA::Allocator::GetMemoryCapacity.
2221
However, it is not recommended, because the amount of memory available to the application
2222
is typically smaller than the full capacity, as some portion of it is reserved by the operating system
2223
or used by other processes.
2224
2225
Because of this, the recommended way of fetching the **memory budget** available to the application
2226
is using function D3D12MA::Allocator::GetBudget.
2227
Preventing value D3D12MA::Budget::UsageBytes from exceeding the D3D12MA::Budget::BudgetBytes
2228
is probably the best we can do in trying to avoid the consequences of over-commitment.
2229
For more information, see also: \subpage statistics.
2230
2231
Example:
2232
2233
\code
2234
D3D12MA::Budget videoMemBudget = {};
2235
allocator->GetBudget(&videoMemBudget, NULL);
2236
2237
UINT64 freeBytes = videoMemBudget.BudgetBytes - videoMemBudget.UsageBytes;
2238
gameStreamingSystem->SetAvailableFreeMemory(freeBytes);
2239
\endcode
2240
2241
\par Implementation detail
2242
DXGI interface offers function `IDXGIAdapter3::QueryVideoMemoryInfo` that queries the current memory usage and budget.
2243
This library automatically makes use of it when available (when you use recent enough version of the DirectX SDK).
2244
If not, it falls back to estimating the usage and budget based on the total amount of the allocated memory
2245
and 80% of the full memory capacity, respectively.
2246
2247
\par Implementation detail
2248
Allocating large heaps and creating placed resources in them is one of the main features of this library.
2249
However, if allocating new such block would exceed the budget, it will automatically prefer creating the resource as committed
2250
to have exactly the right size, which can lower the chance of getting into trouble in case of over-commitment.
2251
2252
When creating non-essential resources, you can use D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET.
2253
Then, in case the allocation would exceed the budget, the library will return failure from the function
2254
without attempting to allocate the actual D3D12 memory.
2255
2256
It may also be a good idea to support failed resource creation.
2257
For non-essential resources, when function D3D12MA::Allocator::CreateResource fails with a result other than `S_OK`,
2258
it is worth implementing some way of recovery instead of terminating or crashing the entire app.
2259
2260
\section optimal_allocation_allocation_Performance Allocation performance
2261
2262
Creating D3D12 resources (buffers and textures) can be a time-consuming operation.
2263
The duration can be unpredictable, spanning from a small fraction of a millisecond to a significant fraction of a second.
2264
Thus, it is recommended to allocate all the memory and create all the resources needed upfront
2265
rather than doing it during application runtime.
2266
For example, a video game can try to create its resources on startup or when loading a new level.
2267
Of course, is is not always possible.
2268
For example, open-world games may require loading and unloading some graphical assets in the background (often called "streaming").
2269
2270
Creating and releasing D3D12 resources **on a separate thread** in the background may help.
2271
Both `ID3D12Device` and D3D12MA::Allocator objects are thread-safe, synchronized internally.
2272
However, cases were observed where resource creation calls like `ID3D12Device::CreateCommittedResource`
2273
were blocking other D3D12 calls like `ExecuteCommandLists` or `Present`
2274
somewhere inside the graphics driver, so hitches can happen even when using multithreading.
2275
2276
The most expensive part is typically **the allocation of a new D3D12 memory heap**.
2277
This library tackles this problem by automatically allocating large heaps (64 MB by default)
2278
and creating resources as placed inside of them.
2279
When a new requested resource can be placed in a free space of an existing heap and doesn't require allocating a new heap,
2280
this operation is typically much faster, as it only requires creating a new `ID3D12Resource` object
2281
and not allocating new memory.
2282
This is the main benefit of using %D3D12MA compared to the naive approach of using Direct3D 12 directly
2283
and creating each resource as committed with `CreateCommittedResource`, which would result in a separate allocation of an implicit heap every time.
2284
2285
When **a large number of small buffers** needs to be created, the overhead of creating even just separate `ID3D12Resource` objects can be significant.
2286
It can be avoided by creating one or few larger buffers and manually sub-allocating parts of them for specific needs.
2287
This library can also help with it. See section "Sub-allocating buffers" below.
2288
2289
\par Implementation detail
2290
The CPU performance overhead of using this library is low.
2291
It uses a high-quality allocation algorithm called Two-Level Segregated Fit (TLSF),
2292
which in most cases can find a free place for a new allocation in few steps.
2293
The library also doesn't perform too many CPU heap allocations.
2294
In may cases, the allocation happens with 0 new CPU heap allocations performed by the library.
2295
Even the creation of a D3D12MA::Allocation object itself doesn't typically feature an CPU allocation,
2296
because these objects are returned out of a dedicated memory pool.
2297
2298
Another reason for the slowness of D3D12 memory allocation is the guarantee that the **newly allocated memory is filled with zeros**.
2299
When creating and destroying resources placed in an existing heap, this overhead is not present,
2300
and the memory is not zeroed - it may contain random data left by the resource previously allocated in that place.
2301
In recent versions of the DirectX 12 SDK, clearing the memory of the newly created D3D12 heaps can also be disabled for the improved performance.
2302
%D3D12MA can use this feature when:
2303
2304
- D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED is used during the creation of the main allocator object.
2305
- `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED` is passed to D3D12MA::POOL_DESC::HeapFlags during the creation of a custom pool.
2306
2307
It is recommended to always use these flags.
2308
The downside is that when the memory is not filled with zeros, while you don't properly clear it or otherwise initialize its content before use
2309
(which is required by D3D12), you may observe incorrect behavior.
2310
This problem mostly affects render-target and depth-stencil textures.
2311
2312
When an allocation needs to be made in a performance-critical code, you can use D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME.
2313
In influences multiple heuristics inside the library to prefer faster allocation
2314
at the expense of possibly less optimal placement in the memory.
2315
2316
If the resource to be created is non-essential, while the performance is paramount,
2317
you can also use D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE.
2318
It will create the resource only if it can be placed inside and existing memory heap
2319
and return failure from the function if a new heap would need to be allocated,
2320
which should guarantee good performance of such function call.
2321
2322
\section optimal_allocation_suballocating_buffers Sub-allocating buffers
2323
2324
When a large number of small buffers needs to be created, the overhead of creating separate `ID3D12Resource` objects can be significant.
2325
It 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.
2326
These problems can be avoided by creating one or few larger buffers and manually sub-allocating parts of them for specific needs.
2327
2328
It requires implementing a custom allocator for the data inside the buffer and using offsets to individual regions.
2329
When all the regions can be allocated linearly and freed all at once, implementing such allocator is trivial.
2330
When every region has the same size, implementing an allocator is also quite simple when using a "free list" algorithm.
2331
However, when regions can have different sizes and can be allocated and freed in random order,
2332
it requires a full allocation algorithm.
2333
%D3D12MA can help with it by exposing its core allocation algorithm for custom usages.
2334
For more details and example code, see chapter: \subpage virtual_allocator.
2335
It can be used for all the cases mentioned above without too much performance overhead,
2336
because the D3D12MA::VirtualAllocation object is just a lightweight handle.
2337
2338
When sub-allocating a buffer, you need to remember to explicitly request proper alignment required for each region.
2339
For example, data used as a constant buffer must be aligned to `D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT` = 256 B.
2340
2341
\section optimal_allocation_residency_priority Residency priority
2342
2343
When too much video memory is allocated, one of the things that can happen is the system
2344
demoting some heaps to the system memory.
2345
Moving data between memory pools or reaching out directly to the system memory through PCI Express bus can have large performance overhead,
2346
which can slow down the application, or even make the game unplayable any more.
2347
Unfortunately, it is not possible to fully control or prevent this demotion.
2348
Best thing to do is avoiding memory over-commitment.
2349
For more information, see section "Avoiding running out of memory" above.
2350
2351
Recent versions of DirectX 12 SDK offer function `ID3D12Device1::SetResidencyPriority` that sets a hint
2352
about the priority of a resource - how important it is to stay resident in the video memory.
2353
Setting the priority happens at the level of an entire memory heap.
2354
%D3D12MA offers an interface to set this priority in form of D3D12MA::POOL_DESC::ResidencyPriority parameter.
2355
It affects all allocations made out of the custom pool created with it, both placed inside large heaps
2356
and created as committed.
2357
2358
It is recommended to create a custom pool for the purpose of using high residency priority
2359
of all resources that are critical for the performance, especially those that are written by the GPU,
2360
like render-target, depth-stencil textures, UAV textures and buffers.
2361
It is also worth creating them as committed, so that each one will have its own implicit heap.
2362
This can minimize the chance that an entire large heap is demoted to system memory, degrading performance
2363
of all the resources placed in it.
2364
2365
Example:
2366
2367
\code
2368
D3D12MA::CPOOL_DESC poolDesc = D3D12MA::CPOOL_DESC{
2369
D3D12_HEAP_TYPE_DEFAULT,
2370
D3D12MA_RECOMMENDED_HEAP_FLAGS | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS };
2371
poolDesc.ResidencyPriority = D3D12_RESIDENCY_PRIORITY_HIGH; // !!!
2372
2373
D3D12MA::Pool* pool;
2374
HRESULT hr = allocator->CreatePool(&poolDesc, &pool);
2375
// Check hr...
2376
2377
D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{
2378
pool,
2379
ALLOCATION_FLAG_COMMITTED }; // !!!
2380
2381
CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(
2382
1048576); // Requested buffer size.
2383
2384
D3D12MA::Allocation* alloc;
2385
hr = allocator->CreateResource(&allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,
2386
NULL, &alloc, IID_NULL, NULL);
2387
// Check hr...
2388
\endcode
2389
2390
When you have a committed allocation created, you can also set the residency priority of its resource
2391
using the D3D12 function:
2392
2393
\code
2394
D3D12MA::Allocation* committedAlloc = ...
2395
ID3D12Pageable* res = committedAlloc->GetResource();
2396
D3D12_RESIDENCY_PRIORITY priority = D3D12_RESIDENCY_PRIORITY_HIGH;
2397
device1->SetResidencyPriority(1, &res, &priority);
2398
\endcode
2399
2400
Note this is not the same as explicit eviction controlled using `ID3D12Device::Evict` and `MakeResident` functions.
2401
Resources evicted explicitly are illegal to access until they are made resident again,
2402
while the demotion described here happens automatically and only slows down the execution.
2403
2404
\section optimal_allocation_gpu_upload_heap GPU upload heap
2405
2406
Direct3D 12 offers a fixed set of memory heap types:
2407
2408
- `D3D12_HEAP_TYPE_DEFAULT`: Represents the video memory. It is available and fast to access for the GPU.
2409
It should be used for all resources that are written by the GPU (like render-target and depth-stencil textures,
2410
UAV) and resources that are frequently read by the GPU (like textures intended for sampling,
2411
vertex, index, and constant buffers).
2412
- `D3D12_HEAP_TYPE_UPLOAD`: Represents the system memory that is uncached and write-combined.
2413
It can be mapped and accessed by the CPU code using a pointer.
2414
It supports only buffers, not textures.
2415
It 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.
2416
It can also be accessed directly by the GPU - shaders can read from buffers created in this memory.
2417
- `D3D12_HEAP_TYPE_READBACK`: Represents the system memory that is cached.
2418
It is intended for buffers used as a destination of copy operations from the `DEFAULT` heap.
2419
2420
Note that in systems with a discrete graphics card, access to system memory is fast from the CPU code
2421
(like the C++ code mapping D3D12 buffers and accessing them through a pointer),
2422
while access to the video memory is fast from the GPU code (like shaders reading and writing buffers and textures).
2423
Any copy operation or direct access between these memory heap types happens through PCI Express bus, which can be relatively slow.
2424
2425
Modern systems offer a feature called **Resizable BAR (ReBAR)** that gives the CPU direct access to the full video memory.
2426
To be available, this feature needs to be supported by the whole hardware-software environment, including:
2427
2428
- Supporting motherboard and its UEFI.
2429
- Supporting graphics card and its graphics driver.
2430
- Supporting operating system.
2431
- The feature needs to be enabled in the UEFI settings. It is typically called "Above 4G Decoding" and "Resizable Bar".
2432
2433
Recent versions of DirectX 12 SDK give access to this feature in form of a new, 4th memory pool: `D3D12_HEAP_TYPE_GPU_UPLOAD`.
2434
Resources created in it behave logically similar to the `D3D12_HEAP_TYPE_UPLOAD` heap:
2435
2436
- They support mapping and direct access from the CPU code through a pointer.
2437
- The mapped memory is uncached and write-combined, so it should be only written sequentially
2438
(e.g., number-by-number or using `memcpy`). It shouldn't be accessed randomly or read,
2439
because it is extremely slow for uncached memory.
2440
- Only buffers are supported.
2441
- Those buffers can be used as a source of copy operations or directly accessed by the GPU.
2442
2443
The main difference is that resources created in the new `D3D12_HEAP_TYPE_GPU_UPLOAD` are placed in the video memory,
2444
while resources created in the old `D3D12_HEAP_TYPE_UPLOAD` are placed in the system memory.
2445
This implies which budgets are consumed by new resources allocated in those heaps.
2446
This also implies which operations involve transferring data through the PCI Express bus.
2447
2448
- As `D3D12_HEAP_TYPE_UPLOAD` uses the system memory, writes from the CPU code through a mapped pointer are faster,
2449
while copies or direct access from the GPU are slower because they need to go through PCIe.
2450
- As the new `D3D12_HEAP_TYPE_GPU_UPLOAD` uses the video memory,
2451
copies or direct access from the GPU are faster,
2452
while writes from the CPU code through a mapped pointer can be slower, because they need to go through PCIe.
2453
For maximum performance of copy operations from this heap, a graphics or compute queue should be used, not a copy queue.
2454
2455
GPU Upload Heap can be used for performance optimization of some resources that need to be written by the CPU and read by the GPU.
2456
It can be beneficial especially for resources that need to change frequently (often called "dynamic").
2457
2458
%D3D12MA supports GPU upload heap when recent enough version of DirectX 12 SDK is used and when the current system supports it.
2459
The support can be queried using function D3D12MA::Allocator::IsGPUUploadHeapSupported().
2460
When it returns `TRUE`, you can create resources using `D3D12_HEAP_TYPE_GPU_UPLOAD`.
2461
You can also just try creating such resource. Example:
2462
2463
\code
2464
D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{
2465
D3D12_HEAP_TYPE_GPU_UPLOAD }; // !!!
2466
2467
CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(
2468
1048576); // Requested buffer size.
2469
2470
D3D12MA::Allocation* alloc;
2471
ID3D12Resource* res;
2472
hr = allocator->CreateResource(&allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,
2473
NULL, &alloc, IID_PPV_ARGS(&res));
2474
if(SUCCEEDED(hr))
2475
{
2476
// Fast path for data upload.
2477
2478
D3D12_RANGE emptyRange = {0, 0};
2479
void* mappedPtr = NULL;
2480
hr = res->Map(0, &emptyRange, &mappedPtr);
2481
memcpy(mappedPtr, srcData, 1048576);
2482
res->Unmap(0, NULL); // Optional. You can leave it persistently mapped.
2483
2484
D3D12_GPU_VIRTUAL_ADDRESS gpuva = res->GetGPUVirtualAddress();
2485
// Use gpuva to access the buffer on the GPU...
2486
}
2487
else if(hr == E_NOTIMPL)
2488
{
2489
// GPU Upload Heap not supported in this system.
2490
// Fall back to creating a staging buffer in UPLOAD and another copy in DEFAULT.
2491
2492
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
2493
// ...
2494
}
2495
else
2496
// Some other error code e.g., out of memory...
2497
\endcode
2498
2499
\section optimal_allocation_committed_vs_placed Committed versus placed resources
2500
2501
When using D3D12 API directly, there are 3 ways of creating resources:
2502
2503
1. **Committed**, using function `ID3D12Device::CreateCommittedResource`.
2504
It creates the resource with its own memory heap, which is called an "implicit heap" and cannot be accessed directly.
2505
2. **Placed**, using function `ID3D12Device::CreatePlacedResource`.
2506
A `ID3D12Heap` needs to be created beforehand using `ID3D12Device::CreateHeap`.
2507
Then, the resource can be created as placed inside the heap at a specific offset.
2508
3. **Reserved**, using function `ID3D12Device::CreateReservedResource`.
2509
This library doesn't support them directly.
2510
2511
A naive solution would be to create all the resources as committed.
2512
It works, because in D3D12 there is no strict limit on the number of resources or heaps that can be created.
2513
However, there are certain advantages and disadvantages of using committed versus placed resources:
2514
2515
- The biggest advantage of using placed resources is the allocation performance.
2516
Once a heap is allocated, creating and releasing resources placed in it can be much faster than
2517
creating them as committed, which would involve allocating a new heap for each resource.
2518
- Using large number of small heaps can put an extra burden on the software stack,
2519
including D3D12 runtime, graphics driver, operating system, and developer tools like Radeon Memory Visualizer (RMV).
2520
- The advantage of committed resources is that their implicit heaps have exactly the right size,
2521
while creating resources as placed inside larger heaps can lead to some memory wasted because:
2522
- Some part of the allocated heap memory is unused.
2523
- After placed resources of various sizes are created and released in random order,
2524
gaps between remaining resources can be too small to fit new allocations.
2525
This is also known as "fragmentation". A solution to this problem is implementing \subpage defragmentation.
2526
- The alignment required by placed resources can leave gaps between them, while the driver can pack individual committed resources better.
2527
For details, see section "Resource alignment" below.
2528
- The advantage of committed resources is that they are always created with a new heap, which is initialized with zeros.
2529
When a resource is created as placed, the memory may contain random data left by the resource previously allocated in that place.
2530
When the memory is not filled with zeros, while you don't properly clear it or otherwise initialize its content before use
2531
(which is required by D3D12), you may observe incorrect behavior.
2532
On the other hand, using committed resources and having every new resource filled with zeros can leave this kind of bugs undetected.
2533
- Manual eviction with `ID3D12Device::Evict` and `MakeResident` functions work at the level of the entire heap,
2534
and so does `ID3D12Device1::SetResidencyPriority`, so creating resources as committed allows more fine-grained control
2535
over the eviction and residency priority of individual resources.
2536
- The advantage of placed resources is that they can be created in a region of a heap overlapping with some other resources.
2537
This approach is commonly called "aliasing".
2538
It can save memory, but it needs careful control over the resources that overlap in memory
2539
to make sure they are not used at the same time, there is an aliasing barrier issued between their usage,
2540
and the resource used after aliasing is correctly cleared every time.
2541
Committed resources don't offer this possibility, because every committed resource has its own exclusive memory heap.
2542
For more information, see chapter \subpage resource_aliasing.
2543
2544
When creating resources with the help of %D3D12MA using function D3D12MA::Allocator::CreateResource,
2545
you typically don't need to care about all this.
2546
The library automatically makes the choice of creating the new resource as committed or placed.
2547
However, in cases when you need the information or the control over this choice between committed and placed,
2548
the library offers facilities to do that, described below.
2549
2550
\par Implementation detail
2551
%D3D12MA creates large heaps (default size is 64 MB) and creates resources as placed in them.
2552
However, it may decide that it is required or preferred to create the specific resource as committed for many reasons, including:
2553
- When the resource is large (larger than half of the default heap size).
2554
- When allocating an entire new heap would exceed the current budget or when we are already over the budget.
2555
- When the resource is a very small buffer. Placed buffers need to be aligned to 64 KB by default,
2556
while creating them as committed can allow the driver to pack them better.
2557
This heuristics can be disabled for an individual resource by using D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME
2558
and for the entire allocator by using D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED.
2559
- When the resource uses non-standard flags specified via D3D12MA::ALLOCATION_DESC::ExtraHeapFlags.
2560
2561
<b>You can check whether an allocation was created as a committed resource</b> by checking if its heap is null.
2562
Committed resources have an implicit heap that is not directly accessible.
2563
2564
\code
2565
bool isCommitted = allocation->GetHeap() == NULL;
2566
\endcode
2567
2568
<b>You can request a new resource to be created as committed</b> by using D3D12MA::ALLOCATION_FLAG_COMMITTED.
2569
Note that committed resources can also be created out of \subpage custom_pools.
2570
2571
You can also request all resources to be created as committed globally for the entire allocator
2572
by using D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED.
2573
However, this contradicts the main purpose of using this library.
2574
It can also prevent certain other features of the library to be used.
2575
This flag should be used only for debugging purposes.
2576
2577
You can create a custom pool with an explicit block size by specifying non-zero D3D12MA::POOL_DESC::BlockSize.
2578
When doing this, all **resources created in such pool are placed** in those blocks (heaps) and never created as committed.
2579
Example:
2580
2581
\code
2582
D3D12MA::CPOOL_DESC poolDesc = D3D12MA::CPOOL_DESC{
2583
D3D12_HEAP_TYPE_DEFAULT,
2584
D3D12MA_RECOMMENDED_HEAP_FLAGS | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS };
2585
poolDesc.BlockSize = 100llu * 1024 * 1024; // 100 MB. Explicit BlockSize guarantees placed.
2586
2587
D3D12MA::Pool* pool;
2588
HRESULT hr = allocator->CreatePool(&poolDesc, &pool);
2589
// Check hr...
2590
2591
D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{ pool };
2592
2593
CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(
2594
90llu * 1024 * 1024); // 90 MB
2595
2596
D3D12MA::Allocation* alloc;
2597
ID3D12Resource* res;
2598
hr = allocator->CreateResource(&allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,
2599
NULL, &alloc, IID_PPV_ARGS(&res));
2600
// Check hr...
2601
2602
// Even a large buffer like this, filling 90% of the block, was created as placed!
2603
assert(alloc->GetHeap() != NULL);
2604
\endcode
2605
2606
<b>You can request a new resource to be created as placed</b> by using D3D12MA::ALLOCATION_FLAG_CAN_ALIAS.
2607
This is required especially if you plan to create another resource in the same region of memory, aliasing with your resource -
2608
hence the name of this flag.
2609
2610
Note D3D12MA::ALLOCATION_FLAG_CAN_ALIAS can be even combined with D3D12MA::ALLOCATION_FLAG_COMMITTED.
2611
In this case, the resource is not created as committed, but it is also not placed as part of a larger heap.
2612
What happens instead is that a new heap is created with the exact size required for the resource,
2613
and the resource is created in it, placed at offset 0.
2614
2615
\section optimal_allocation_resource_alignment Resource alignment
2616
2617
Certain types of resources require certain alignment in memory.
2618
An 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.
2619
For committed resources, the problem is non-existent, because committed resources have their own implicit heaps
2620
where they are created at offset 0, which meets any alignment requirement.
2621
For placed resources, %D3D12MA takes care of the alignment automatically.
2622
2623
\par Implementation detail
2624
Default alignment required MSAA textures is `D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT` = 4 MB.
2625
Default alignment required for buffers and other textures is `D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT` = 64 KB.
2626
2627
Because the alignment required for buffers is 64 KB, **small buffers** can waste a lot of memory in between when created as placed.
2628
When such small buffers are created as committed, some graphics drivers are able to pack them better.
2629
%D3D12MA automatically takes advantage of this by preferring to create small buffers as committed.
2630
This heuristics is enabled by default. It is also a tradeoff - it can make the allocation of these buffers slower.
2631
It can be disabled for an individual resource by using D3D12MA::ALLOCATION_FLAG_STRATEGY_MIN_TIME
2632
and for the entire allocator by using D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED.
2633
2634
For certain textures that meet a complex set of requirements, special **"small alignment"** can be applied.
2635
Details can be found in Microsoft documentation of the `D3D12_RESOURCE_DESC` structure.
2636
For MSAA textures, the small alignment is `D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT` = 64 KB.
2637
For other textures, the small alignment is `D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT` = 4 KB.
2638
%D3D12MA uses this feature automatically.
2639
Detailed behavior can be disabled or controlled by predefining macro #D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT.
2640
2641
D3D12 also has a concept of **alignment of the entire heap**, passed through `D3D12_HEAP_DESC::Alignment`.
2642
This library automatically sets the alignment as small as possible.
2643
Unfortunately, any heap that has a chance of hosting an MSAA texture needs to have the alignment set to 4 MB.
2644
This problem can be overcome by passing D3D12MA::ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED on the creation of the main allocator object
2645
and D3D12MA::POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED on the creation of any custom heap that supports textures, not only buffers.
2646
With those flags, the alignment of the heaps created by %D3D12MA can be lower, but any MSAA textures are created as committed.
2647
You should always use these flags in your code unless you really need to create some MSAA textures as placed.
2648
2649
\page defragmentation Defragmentation
2650
2651
Interleaved allocations and deallocations of many objects of varying size can
2652
cause fragmentation over time, which can lead to a situation where the library is unable
2653
to find a continuous range of free memory for a new allocation despite there is
2654
enough free space, just scattered across many small free ranges between existing
2655
allocations.
2656
2657
To mitigate this problem, you can use defragmentation feature.
2658
It doesn't happen automatically though and needs your cooperation,
2659
because %D3D12MA is a low level library that only allocates memory.
2660
It cannot recreate buffers and textures in a new place as it doesn't remember the contents of `D3D12_RESOURCE_DESC` structure.
2661
It cannot copy their contents as it doesn't record any commands to a command list.
2662
2663
Example:
2664
2665
\code
2666
D3D12MA::DEFRAGMENTATION_DESC defragDesc = {};
2667
defragDesc.Flags = D3D12MA::DEFRAGMENTATION_FLAG_ALGORITHM_FAST;
2668
2669
D3D12MA::DefragmentationContext* defragCtx;
2670
allocator->BeginDefragmentation(&defragDesc, &defragCtx);
2671
2672
for(;;)
2673
{
2674
D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO pass;
2675
HRESULT hr = defragCtx->BeginPass(&pass);
2676
if(hr == S_OK)
2677
break;
2678
else if(hr != S_FALSE)
2679
// Handle error...
2680
2681
for(UINT i = 0; i < pass.MoveCount; ++i)
2682
{
2683
// Inspect pass.pMoves[i].pSrcAllocation, identify what buffer/texture it represents.
2684
MyEngineResourceData* resData = (MyEngineResourceData*)pMoves[i].pSrcAllocation->GetPrivateData();
2685
2686
// Recreate this buffer/texture as placed at pass.pMoves[i].pDstTmpAllocation.
2687
D3D12_RESOURCE_DESC resDesc = ...
2688
ID3D12Resource* newRes;
2689
hr = device->CreatePlacedResource(
2690
pass.pMoves[i].pDstTmpAllocation->GetHeap(),
2691
pass.pMoves[i].pDstTmpAllocation->GetOffset(), &resDesc,
2692
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&newRes));
2693
// Check hr...
2694
2695
// Store new resource in the pDstTmpAllocation.
2696
pass.pMoves[i].pDstTmpAllocation->SetResource(newRes);
2697
2698
// Copy its content to the new place.
2699
cmdList->CopyResource(
2700
pass.pMoves[i].pDstTmpAllocation->GetResource(),
2701
pass.pMoves[i].pSrcAllocation->GetResource());
2702
}
2703
2704
// Make sure the copy commands finished executing.
2705
cmdQueue->ExecuteCommandLists(...);
2706
// ...
2707
WaitForSingleObject(fenceEvent, INFINITE);
2708
2709
// Update appropriate descriptors to point to the new places...
2710
2711
hr = defragCtx->EndPass(&pass);
2712
if(hr == S_OK)
2713
break;
2714
else if(hr != S_FALSE)
2715
// Handle error...
2716
}
2717
2718
defragCtx->Release();
2719
\endcode
2720
2721
Although functions like D3D12MA::Allocator::CreateResource()
2722
create an allocation and a buffer/texture at once, these are just a shortcut for
2723
allocating memory and creating a placed resource.
2724
Defragmentation works on memory allocations only. You must handle the rest manually.
2725
Defragmentation is an iterative process that should repreat "passes" as long as related functions
2726
return `S_FALSE` not `S_OK`.
2727
In each pass:
2728
2729
1. D3D12MA::DefragmentationContext::BeginPass() function call:
2730
- Calculates and returns the list of allocations to be moved in this pass.
2731
Note this can be a time-consuming process.
2732
- Reserves destination memory for them by creating temporary destination allocations
2733
that you can query for their `ID3D12Heap` + offset using methods like D3D12MA::Allocation::GetHeap().
2734
2. Inside the pass, **you should**:
2735
- Inspect the returned list of allocations to be moved.
2736
- Create new buffers/textures as placed at the returned destination temporary allocations.
2737
- Copy data from source to destination resources if necessary.
2738
- Store the pointer to the new resource in the temporary destination allocation.
2739
3. D3D12MA::DefragmentationContext::EndPass() function call:
2740
- Frees the source memory reserved for the allocations that are moved.
2741
- Modifies source D3D12MA::Allocation objects that are moved to point to the destination reserved memory
2742
and destination resource, while source resource is released.
2743
- Frees `ID3D12Heap` blocks that became empty.
2744
2745
Defragmentation algorithm tries to move all suitable allocations.
2746
You can, however, refuse to move some of them inside a defragmentation pass, by setting
2747
`pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
2748
This is not recommended and may result in suboptimal packing of the allocations after defragmentation.
2749
If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.
2750
2751
Inside a pass, for each allocation that should be moved:
2752
2753
- You should copy its data from the source to the destination place by calling e.g. `CopyResource()`.
2754
- You need to make sure these commands finished executing before the source buffers/textures are released by D3D12MA::DefragmentationContext::EndPass().
2755
- If a resource doesn't contain any meaningful data, e.g. it is a transient render-target texture to be cleared,
2756
filled, and used temporarily in each rendering frame, you can just recreate this texture
2757
without copying its data.
2758
- If the resource is in `D3D12_HEAP_TYPE_READBACK` memory, you can copy its data on the CPU
2759
using `memcpy()`.
2760
- If you cannot move the allocation, you can set `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
2761
This will cancel the move.
2762
- D3D12MA::DefragmentationContext::EndPass() will then free the destination memory
2763
not the source memory of the allocation, leaving it unchanged.
2764
- If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time),
2765
you can set `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY.
2766
- D3D12MA::DefragmentationContext::EndPass() will then free both source and destination memory, and will destroy the source D3D12MA::Allocation object.
2767
2768
You can defragment a specific custom pool by calling D3D12MA::Pool::BeginDefragmentation
2769
or all the default pools by calling D3D12MA::Allocator::BeginDefragmentation (like in the example above).
2770
2771
Defragmentation is always performed in each pool separately.
2772
Allocations are never moved between different heap types.
2773
The size of the destination memory reserved for a moved allocation is the same as the original one.
2774
Alignment of an allocation as it was determined using `GetResourceAllocationInfo()` is also respected after defragmentation.
2775
Buffers/textures should be recreated with the same `D3D12_RESOURCE_DESC` parameters as the original ones.
2776
2777
You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved
2778
in each pass, e.g. to call it in sync with render frames and not to experience too big hitches.
2779
See members: D3D12MA::DEFRAGMENTATION_DESC::MaxBytesPerPass, D3D12MA::DEFRAGMENTATION_DESC::MaxAllocationsPerPass.
2780
2781
<b>Thread safety:</b>
2782
It is safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and %D3D12MA
2783
usage, possibly from multiple threads, with the exception that allocations
2784
returned in D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO::pMoves shouldn't be released until the defragmentation pass is ended.
2785
During the call to D3D12MA::DefragmentationContext::BeginPass(), any operations on the memory pool
2786
affected by the defragmentation are blocked by a mutex.
2787
2788
What it means in practice is that you shouldn't free any allocations from the defragmented pool
2789
since the moment a call to `BeginPass` begins. Otherwise, a thread performing the `allocation->Release()`
2790
would block for the time `BeginPass` executes and then free the allocation when it finishes, while the allocation
2791
could have ended up on the list of allocations to move.
2792
A solution to freeing allocations during defragmentation is to find such allocation on the list
2793
`pass.pMoves[i]` and set its operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY instead of
2794
calling `allocation->Release()`, or simply deferring the release to the time after defragmentation finished.
2795
2796
<b>Mapping</b> is out of scope of this library and so it is not preserved after an allocation is moved during defragmentation.
2797
You need to map the new resource yourself if needed.
2798
2799
\note Defragmentation is not supported in custom pools created with D3D12MA::POOL_FLAG_ALGORITHM_LINEAR.
2800
2801
2802
\page statistics Statistics
2803
2804
This library contains several functions that return information about its internal state,
2805
especially the amount of memory allocated from D3D12.
2806
2807
\section statistics_numeric_statistics Numeric statistics
2808
2809
If you need to obtain basic statistics about memory usage per memory segment group, together with current budget,
2810
you can call function D3D12MA::Allocator::GetBudget() and inspect structure D3D12MA::Budget.
2811
This is useful to keep track of memory usage and stay withing budget.
2812
Example:
2813
2814
\code
2815
D3D12MA::Budget localBudget;
2816
allocator->GetBudget(&localBudget, NULL);
2817
2818
printf("My GPU memory currently has %u allocations taking %llu B,\n",
2819
localBudget.Statistics.AllocationCount,
2820
localBudget.Statistics.AllocationBytes);
2821
printf("allocated out of %u D3D12 memory heaps taking %llu B,\n",
2822
localBudget.Statistics.BlockCount,
2823
localBudget.Statistics.BlockBytes);
2824
printf("D3D12 reports total usage %llu B with budget %llu B.\n",
2825
localBudget.UsageBytes,
2826
localBudget.BudgetBytes);
2827
\endcode
2828
2829
You can query for more detailed statistics per heap type, memory segment group, and totals,
2830
including minimum and maximum allocation size and unused range size,
2831
by calling function D3D12MA::Allocator::CalculateStatistics() and inspecting structure D3D12MA::TotalStatistics.
2832
This function is slower though, as it has to traverse all the internal data structures,
2833
so it should be used only for debugging purposes.
2834
2835
You can query for statistics of a custom pool using function D3D12MA::Pool::GetStatistics()
2836
or D3D12MA::Pool::CalculateStatistics().
2837
2838
You can query for information about a specific allocation using functions of the D3D12MA::Allocation class,
2839
e.g. `GetSize()`, `GetOffset()`, `GetHeap()`.
2840
2841
\section statistics_json_dump JSON dump
2842
2843
You can dump internal state of the allocator to a string in JSON format using function D3D12MA::Allocator::BuildStatsString().
2844
The result is guaranteed to be correct JSON.
2845
It uses Windows Unicode (UTF-16) encoding.
2846
Any strings provided by user (see D3D12MA::Allocation::SetName())
2847
are copied as-is and properly escaped for JSON.
2848
It must be freed using function D3D12MA::Allocator::FreeStatsString().
2849
2850
The format of this JSON string is not part of official documentation of the library,
2851
but it will not change in backward-incompatible way without increasing library major version number
2852
and appropriate mention in changelog.
2853
2854
The JSON string contains all the data that can be obtained using D3D12MA::Allocator::CalculateStatistics().
2855
It can also contain detailed map of allocated memory blocks and their regions -
2856
free and occupied by allocations.
2857
This allows e.g. to visualize the memory or assess fragmentation.
2858
2859
2860
\page resource_aliasing Resource aliasing (overlap)
2861
2862
New explicit graphics APIs (Vulkan and Direct3D 12), thanks to manual memory
2863
management, give an opportunity to alias (overlap) multiple resources in the
2864
same region of memory - a feature not available in the old APIs (Direct3D 11, OpenGL).
2865
It can be useful to save video memory, but it must be used with caution.
2866
2867
For example, if you know the flow of your whole render frame in advance, you
2868
are going to use some intermediate textures or buffers only during a small range of render passes,
2869
and you know these ranges don't overlap in time, you can create these resources in
2870
the same place in memory, even if they have completely different parameters (width, height, format etc.).
2871
2872
![Resource aliasing (overlap)](../gfx/Aliasing.png)
2873
2874
Such scenario is possible using D3D12MA, but you need to create your resources
2875
using special function D3D12MA::Allocator::CreateAliasingResource.
2876
Before that, you need to allocate memory with parameters calculated using formula:
2877
2878
- allocation size = max(size of each resource)
2879
- allocation alignment = max(alignment of each resource)
2880
2881
Following example shows two different textures created in the same place in memory,
2882
allocated to fit largest of them.
2883
2884
\code
2885
D3D12_RESOURCE_DESC resDesc1 = {};
2886
resDesc1.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
2887
resDesc1.Alignment = 0;
2888
resDesc1.Width = 1920;
2889
resDesc1.Height = 1080;
2890
resDesc1.DepthOrArraySize = 1;
2891
resDesc1.MipLevels = 1;
2892
resDesc1.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2893
resDesc1.SampleDesc.Count = 1;
2894
resDesc1.SampleDesc.Quality = 0;
2895
resDesc1.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
2896
resDesc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
2897
2898
D3D12_RESOURCE_DESC resDesc2 = {};
2899
resDesc2.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
2900
resDesc2.Alignment = 0;
2901
resDesc2.Width = 1024;
2902
resDesc2.Height = 1024;
2903
resDesc2.DepthOrArraySize = 1;
2904
resDesc2.MipLevels = 0;
2905
resDesc2.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2906
resDesc2.SampleDesc.Count = 1;
2907
resDesc2.SampleDesc.Quality = 0;
2908
resDesc2.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
2909
resDesc2.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
2910
2911
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo1 =
2912
device->GetResourceAllocationInfo(0, 1, &resDesc1);
2913
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo2 =
2914
device->GetResourceAllocationInfo(0, 1, &resDesc2);
2915
2916
D3D12_RESOURCE_ALLOCATION_INFO finalAllocInfo = {};
2917
finalAllocInfo.Alignment = std::max(allocInfo1.Alignment, allocInfo2.Alignment);
2918
finalAllocInfo.SizeInBytes = std::max(allocInfo1.SizeInBytes, allocInfo2.SizeInBytes);
2919
2920
D3D12MA::ALLOCATION_DESC allocDesc = {};
2921
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
2922
allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
2923
2924
D3D12MA::Allocation* alloc;
2925
hr = allocator->AllocateMemory(&allocDesc, &finalAllocInfo, &alloc);
2926
assert(alloc != NULL && alloc->GetHeap() != NULL);
2927
2928
ID3D12Resource* res1;
2929
hr = allocator->CreateAliasingResource(
2930
alloc,
2931
0, // AllocationLocalOffset
2932
&resDesc1,
2933
D3D12_RESOURCE_STATE_COMMON,
2934
NULL, // pOptimizedClearValue
2935
IID_PPV_ARGS(&res1));
2936
2937
ID3D12Resource* res2;
2938
hr = allocator->CreateAliasingResource(
2939
alloc,
2940
0, // AllocationLocalOffset
2941
&resDesc2,
2942
D3D12_RESOURCE_STATE_COMMON,
2943
NULL, // pOptimizedClearValue
2944
IID_PPV_ARGS(&res2));
2945
2946
// You can use res1 and res2, but not at the same time!
2947
2948
res2->Release();
2949
res1->Release();
2950
alloc->Release();
2951
\endcode
2952
2953
Remember that using resouces that alias in memory requires proper synchronization.
2954
You need to issue a special barrier of type `D3D12_RESOURCE_BARRIER_TYPE_ALIASING`.
2955
You also need to treat a resource after aliasing as uninitialized - containing garbage data.
2956
For example, if you use `res1` and then want to use `res2`, you need to first initialize `res2`
2957
using either Clear, Discard, or Copy to the entire resource.
2958
2959
Additional considerations:
2960
2961
- D3D12 also allows to interpret contents of memory between aliasing resources consistently in some cases,
2962
which is called "data inheritance". For details, see
2963
Microsoft documentation chapter "Memory Aliasing and Data Inheritance".
2964
- You can create more complex layout where different textures and buffers are bound
2965
at different offsets inside one large allocation. For example, one can imagine
2966
a big texture used in some render passes, aliasing with a set of many small buffers
2967
used in some further passes. To bind a resource at non-zero offset of an allocation,
2968
call D3D12MA::Allocator::CreateAliasingResource with appropriate value of `AllocationLocalOffset` parameter.
2969
- Resources of the three categories: buffers, textures with `RENDER_TARGET` or `DEPTH_STENCIL` flags, and all other textures,
2970
can be placed in the same memory only when `allocator->GetD3D12Options().ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2`.
2971
Otherwise they must be placed in different memory heap types, and thus aliasing them is not possible.
2972
2973
2974
\page linear_algorithm Linear allocation algorithm
2975
2976
Each D3D12 memory block managed by this library has accompanying metadata that
2977
keeps track of used and unused regions. By default, the metadata structure and
2978
algorithm tries to find best place for new allocations among free regions to
2979
optimize memory usage. This way you can allocate and free objects in any order.
2980
2981
![Default allocation algorithm](../gfx/Linear_allocator_1_algo_default.png)
2982
2983
Sometimes there is a need to use simpler, linear allocation algorithm. You can
2984
create custom pool that uses such algorithm by adding flag
2985
D3D12MA::POOL_FLAG_ALGORITHM_LINEAR to D3D12MA::POOL_DESC::Flags while creating
2986
D3D12MA::Pool object. Then an alternative metadata management is used. It always
2987
creates new allocations after last one and doesn't reuse free regions after
2988
allocations freed in the middle. It results in better allocation performance and
2989
less memory consumed by metadata.
2990
2991
![Linear allocation algorithm](../gfx/Linear_allocator_2_algo_linear.png)
2992
2993
With this one flag, you can create a custom pool that can be used in many ways:
2994
free-at-once, stack, double stack, and ring buffer. See below for details.
2995
You don't need to specify explicitly which of these options you are going to use - it is detected automatically.
2996
2997
\section linear_algorithm_free_at_once Free-at-once
2998
2999
In a pool that uses linear algorithm, you still need to free all the allocations
3000
individually by calling `allocation->Release()`. You can free
3001
them in any order. New allocations are always made after last one - free space
3002
in the middle is not reused. However, when you release all the allocation and
3003
the pool becomes empty, allocation starts from the beginning again. This way you
3004
can use linear algorithm to speed up creation of allocations that you are going
3005
to release all at once.
3006
3007
![Free-at-once](../gfx/Linear_allocator_3_free_at_once.png)
3008
3009
This mode is also available for pools created with D3D12MA::POOL_DESC::MaxBlockCount
3010
value that allows multiple memory blocks.
3011
3012
\section linear_algorithm_stack Stack
3013
3014
When you free an allocation that was created last, its space can be reused.
3015
Thanks to this, if you always release allocations in the order opposite to their
3016
creation (LIFO - Last In First Out), you can achieve behavior of a stack.
3017
3018
![Stack](../gfx/Linear_allocator_4_stack.png)
3019
3020
This mode is also available for pools created with D3D12MA::POOL_DESC::MaxBlockCount
3021
value that allows multiple memory blocks.
3022
3023
\section linear_algorithm_double_stack Double stack
3024
3025
The space reserved by a custom pool with linear algorithm may be used by two
3026
stacks:
3027
3028
- First, default one, growing up from offset 0.
3029
- Second, "upper" one, growing down from the end towards lower offsets.
3030
3031
To make allocation from the upper stack, add flag D3D12MA::ALLOCATION_FLAG_UPPER_ADDRESS
3032
to D3D12MA::ALLOCATION_DESC::Flags.
3033
3034
![Double stack](../gfx/Linear_allocator_7_double_stack.png)
3035
3036
Double stack is available only in pools with one memory block -
3037
D3D12MA::POOL_DESC::MaxBlockCount must be 1. Otherwise behavior is undefined.
3038
3039
When the two stacks' ends meet so there is not enough space between them for a
3040
new allocation, such allocation fails with usual `E_OUTOFMEMORY` error.
3041
3042
\section linear_algorithm_ring_buffer Ring buffer
3043
3044
When you free some allocations from the beginning and there is not enough free space
3045
for a new one at the end of a pool, allocator's "cursor" wraps around to the
3046
beginning and starts allocation there. Thanks to this, if you always release
3047
allocations in the same order as you created them (FIFO - First In First Out),
3048
you can achieve behavior of a ring buffer / queue.
3049
3050
![Ring buffer](../gfx/Linear_allocator_5_ring_buffer.png)
3051
3052
Ring buffer is available only in pools with one memory block -
3053
D3D12MA::POOL_DESC::MaxBlockCount must be 1. Otherwise behavior is undefined.
3054
3055
\section linear_algorithm_additional_considerations Additional considerations
3056
3057
Linear algorithm can also be used with \ref virtual_allocator.
3058
See flag D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR.
3059
3060
3061
\page virtual_allocator Virtual allocator
3062
3063
As an extra feature, the core allocation algorithm of the library is exposed through a simple and convenient API of "virtual allocator".
3064
It doesn't allocate any real GPU memory. It just keeps track of used and free regions of a "virtual block".
3065
You can use it to allocate your own memory or other objects, even completely unrelated to D3D12.
3066
A common use case is sub-allocation of pieces of one large GPU buffer.
3067
Another suggested use case is allocating descriptors in a `ID3D12DescriptorHeap`.
3068
3069
\section virtual_allocator_creating_virtual_block Creating virtual block
3070
3071
To use this functionality, there is no main "allocator" object.
3072
You don't need to have D3D12MA::Allocator object created.
3073
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:
3074
3075
-# Fill in D3D12MA::ALLOCATOR_DESC structure.
3076
-# Call D3D12MA::CreateVirtualBlock. Get new D3D12MA::VirtualBlock object.
3077
3078
Example:
3079
3080
\code
3081
D3D12MA::VIRTUAL_BLOCK_DESC blockDesc = {};
3082
blockDesc.Size = 1048576; // 1 MB
3083
3084
D3D12MA::VirtualBlock *block;
3085
HRESULT hr = CreateVirtualBlock(&blockDesc, &block);
3086
\endcode
3087
3088
\section virtual_allocator_making_virtual_allocations Making virtual allocations
3089
3090
D3D12MA::VirtualBlock object contains internal data structure that keeps track of free and occupied regions
3091
using the same code as the main D3D12 memory allocator.
3092
A single allocation is identified by a lightweight structure D3D12MA::VirtualAllocation.
3093
You will also likely want to know the offset at which the allocation was made in the block.
3094
3095
In order to make an allocation:
3096
3097
-# Fill in D3D12MA::VIRTUAL_ALLOCATION_DESC structure.
3098
-# Call D3D12MA::VirtualBlock::Allocate. Get new D3D12MA::VirtualAllocation value that identifies the allocation.
3099
3100
Example:
3101
3102
\code
3103
D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};
3104
allocDesc.Size = 4096; // 4 KB
3105
3106
D3D12MA::VirtualAllocation alloc;
3107
UINT64 allocOffset;
3108
hr = block->Allocate(&allocDesc, &alloc, &allocOffset);
3109
if(SUCCEEDED(hr))
3110
{
3111
// Use the 4 KB of your memory starting at allocOffset.
3112
}
3113
else
3114
{
3115
// Allocation failed - no space for it could be found. Handle this error!
3116
}
3117
\endcode
3118
3119
\section virtual_allocator_deallocation Deallocation
3120
3121
When no longer needed, an allocation can be freed by calling D3D12MA::VirtualBlock::FreeAllocation.
3122
3123
When whole block is no longer needed, the block object can be released by calling `block->Release()`.
3124
All allocations must be freed before the block is destroyed, which is checked internally by an assert.
3125
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 -
3126
a feature not available in normal D3D12 memory allocator.
3127
3128
Example:
3129
3130
\code
3131
block->FreeAllocation(alloc);
3132
block->Release();
3133
\endcode
3134
3135
\section virtual_allocator_allocation_parameters Allocation parameters
3136
3137
You can attach a custom pointer to each allocation by using D3D12MA::VirtualBlock::SetAllocationPrivateData.
3138
Its default value is `NULL`.
3139
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
3140
larger data structure containing more information. Example:
3141
3142
\code
3143
struct CustomAllocData
3144
{
3145
std::string m_AllocName;
3146
};
3147
CustomAllocData* allocData = new CustomAllocData();
3148
allocData->m_AllocName = "My allocation 1";
3149
block->SetAllocationPrivateData(alloc, allocData);
3150
\endcode
3151
3152
The pointer can later be fetched, along with allocation offset and size, by passing the allocation handle to function
3153
D3D12MA::VirtualBlock::GetAllocationInfo and inspecting returned structure D3D12MA::VIRTUAL_ALLOCATION_INFO.
3154
If you allocated a new object to be used as the custom pointer, don't forget to delete that object before freeing the allocation!
3155
Example:
3156
3157
\code
3158
VIRTUAL_ALLOCATION_INFO allocInfo;
3159
block->GetAllocationInfo(alloc, &allocInfo);
3160
delete (CustomAllocData*)allocInfo.pPrivateData;
3161
3162
block->FreeAllocation(alloc);
3163
\endcode
3164
3165
\section virtual_allocator_alignment_and_units Alignment and units
3166
3167
It feels natural to express sizes and offsets in bytes.
3168
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
3169
D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment to request it. Example:
3170
3171
\code
3172
D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};
3173
allocDesc.Size = 4096; // 4 KB
3174
allocDesc.Alignment = 4; // Returned offset must be a multiply of 4 B
3175
3176
D3D12MA::VirtualAllocation alloc;
3177
UINT64 allocOffset;
3178
hr = block->Allocate(&allocDesc, &alloc, &allocOffset);
3179
\endcode
3180
3181
Alignments of different allocations made from one block may vary.
3182
However, if all alignments and sizes are always multiply of some size e.g. 4 B or `sizeof(MyDataStruct)`,
3183
you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes.
3184
It might be more convenient, but you need to make sure to use this new unit consistently in all the places:
3185
3186
- D3D12MA::VIRTUAL_BLOCK_DESC::Size
3187
- D3D12MA::VIRTUAL_ALLOCATION_DESC::Size and D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment
3188
- Using offset returned by D3D12MA::VirtualBlock::Allocate and D3D12MA::VIRTUAL_ALLOCATION_INFO::Offset
3189
3190
\section virtual_allocator_statistics Statistics
3191
3192
You can obtain brief statistics of a virtual block using D3D12MA::VirtualBlock::GetStatistics().
3193
The function fills structure D3D12MA::Statistics - same as used by the normal D3D12 memory allocator.
3194
Example:
3195
3196
\code
3197
D3D12MA::Statistics stats;
3198
block->GetStatistics(&stats);
3199
printf("My virtual block has %llu bytes used by %u virtual allocations\n",
3200
stats.AllocationBytes, stats.AllocationCount);
3201
\endcode
3202
3203
More detailed statistics can be obtained using function D3D12MA::VirtualBlock::CalculateStatistics(),
3204
but they are slower to calculate.
3205
3206
You can also request a full list of allocations and free regions as a string in JSON format by calling
3207
D3D12MA::VirtualBlock::BuildStatsString.
3208
Returned string must be later freed using D3D12MA::VirtualBlock::FreeStatsString.
3209
The format of this string may differ from the one returned by the main D3D12 allocator, but it is similar.
3210
3211
\section virtual_allocator_additional_considerations Additional considerations
3212
3213
Alternative, linear algorithm can be used with virtual allocator - see flag
3214
D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR and documentation: \ref linear_algorithm.
3215
3216
Note that the "virtual allocator" functionality is implemented on a level of individual memory blocks.
3217
Keeping track of a whole collection of blocks, allocating new ones when out of free space,
3218
deleting empty ones, and deciding which one to try first for a new allocation must be implemented by the user.
3219
3220
3221
\page configuration Configuration
3222
3223
Please check file `D3D12MemAlloc.cpp` lines between "Configuration Begin" and
3224
"Configuration End" to find macros that you can define to change the behavior of
3225
the library, primarily for debugging purposes.
3226
3227
\section custom_memory_allocator Custom CPU memory allocator
3228
3229
If you use custom allocator for CPU memory rather than default C++ operator `new`
3230
and `delete` or `malloc` and `free` functions, you can make this library using
3231
your allocator as well by filling structure D3D12MA::ALLOCATION_CALLBACKS and
3232
passing it as optional member D3D12MA::ALLOCATOR_DESC::pAllocationCallbacks.
3233
Functions pointed there will be used by the library to make any CPU-side
3234
allocations. Example:
3235
3236
\code
3237
#include <malloc.h>
3238
3239
void* CustomAllocate(size_t Size, size_t Alignment, void* pPrivateData)
3240
{
3241
void* memory = _aligned_malloc(Size, Alignment);
3242
// Your extra bookkeeping here...
3243
return memory;
3244
}
3245
3246
void CustomFree(void* pMemory, void* pPrivateData)
3247
{
3248
// Your extra bookkeeping here...
3249
_aligned_free(pMemory);
3250
}
3251
3252
...
3253
3254
D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};
3255
allocationCallbacks.pAllocate = &CustomAllocate;
3256
allocationCallbacks.pFree = &CustomFree;
3257
3258
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3259
allocatorDesc.pDevice = device;
3260
allocatorDesc.pAdapter = adapter;
3261
allocatorDesc.Flags = D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS;
3262
allocatorDesc.pAllocationCallbacks = &allocationCallbacks;
3263
3264
D3D12MA::Allocator* allocator;
3265
HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3266
// Check hr...
3267
\endcode
3268
3269
3270
\section debug_margins Debug margins
3271
3272
By default, allocations are laid out in memory blocks next to each other if possible
3273
(considering required alignment returned by `ID3D12Device::GetResourceAllocationInfo`).
3274
3275
![Allocations without margin](../gfx/Margins_1.png)
3276
3277
Define macro `D3D12MA_DEBUG_MARGIN` to some non-zero value (e.g. 16) inside "D3D12MemAlloc.cpp"
3278
to enforce specified number of bytes as a margin after every allocation.
3279
3280
![Allocations with margin](../gfx/Margins_2.png)
3281
3282
If your bug goes away after enabling margins, it means it may be caused by memory
3283
being overwritten outside of allocation boundaries. It is not 100% certain though.
3284
Change in application behavior may also be caused by different order and distribution
3285
of allocations across memory blocks after margins are applied.
3286
3287
Margins work with all memory heap types.
3288
3289
Margin is applied only to placed allocations made out of memory heaps and not to committed
3290
allocations, which have their own, implicit memory heap of specific size.
3291
It is thus not applied to allocations made using D3D12MA::ALLOCATION_FLAG_COMMITTED flag
3292
or those automatically decided to put into committed allocations, e.g. due to its large size.
3293
3294
Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space.
3295
3296
Note that enabling margins increases memory usage and fragmentation.
3297
3298
Margins do not apply to \ref virtual_allocator.
3299
3300
3301
\page general_considerations General considerations
3302
3303
\section general_considerations_thread_safety Thread safety
3304
3305
- The library has no global state, so separate D3D12MA::Allocator objects can be used independently.
3306
In typical applications there should be no need to create multiple such objects though - one per `ID3D12Device` is enough.
3307
- All calls to methods of D3D12MA::Allocator class are safe to be made from multiple
3308
threads simultaneously because they are synchronized internally when needed.
3309
- When the allocator is created with D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED,
3310
calls to methods of D3D12MA::Allocator class must be made from a single thread or synchronized by the user.
3311
Using this flag may improve performance.
3312
- D3D12MA::VirtualBlock is not safe to be used from multiple threads simultaneously.
3313
3314
\section general_considerations_versioning_and_compatibility Versioning and compatibility
3315
3316
The library uses [**Semantic Versioning**](https://semver.org/),
3317
which means version numbers follow convention: Major.Minor.Patch (e.g. 2.3.0), where:
3318
3319
- Incremented Patch version means a release is backward- and forward-compatible,
3320
introducing only some internal improvements, bug fixes, optimizations etc.
3321
or changes that are out of scope of the official API described in this documentation.
3322
- Incremented Minor version means a release is backward-compatible,
3323
so existing code that uses the library should continue to work, while some new
3324
symbols could have been added: new structures, functions, new values in existing
3325
enums and bit flags, new structure members, but not new function parameters.
3326
- Incrementing Major version means a release could break some backward compatibility.
3327
3328
All changes between official releases are documented in file "CHANGELOG.md".
3329
3330
\warning Backward compatiblity is considered on the level of C++ source code, not binary linkage.
3331
Adding new members to existing structures is treated as backward compatible if initializing
3332
the new members to binary zero results in the old behavior.
3333
You should always fully initialize all library structures to zeros and not rely on their
3334
exact binary size.
3335
3336
\section general_considerations_features_not_supported Features not supported
3337
3338
Features deliberately excluded from the scope of this library:
3339
3340
- **Descriptor allocation.** Although also called "heaps", objects that represent
3341
descriptors are separate part of the D3D12 API from buffers and textures.
3342
You can still use \ref virtual_allocator to manage descriptors and their ranges inside a descriptor heap.
3343
- **Support for reserved (tiled) resources.** We don't recommend using them.
3344
- Support for `ID3D12Device::Evict` and `MakeResident`. We don't recommend using them.
3345
You can call them on the D3D12 objects manually.
3346
Plese keep in mind, however, that eviction happens on the level of entire `ID3D12Heap` memory blocks
3347
and not individual buffers or textures which may be placed inside them.
3348
- **Handling CPU memory allocation failures.** When dynamically creating small C++
3349
objects in CPU memory (not the GPU memory), allocation failures are not
3350
handled gracefully, because that would complicate code significantly and
3351
is usually not needed in desktop PC applications anyway.
3352
Success of an allocation is just checked with an assert.
3353
- **Code free of any compiler warnings.**
3354
There are many preprocessor macros that make some variables unused, function parameters unreferenced,
3355
or conditional expressions constant in some configurations.
3356
The code of this library should not be bigger or more complicated just to silence these warnings.
3357
It is recommended to disable such warnings instead.
3358
- This is a C++ library. **Bindings or ports to any other programming languages** are welcome as external projects but
3359
are not going to be included into this repository.
3360
*/
3361
3362