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