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