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