1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632 |
- //
- // Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #pragma once
- /** \mainpage D3D12 Memory Allocator
- <b>Version 2.1.0-development</b> (2022-12-15)
- Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved. \n
- License: MIT
- Documentation of all members: D3D12MemAlloc.h
- \section main_table_of_contents Table of contents
- - \subpage quick_start
- - [Project setup](@ref quick_start_project_setup)
- - [Creating resources](@ref quick_start_creating_resources)
- - [Resource reference counting](@ref quick_start_resource_reference_counting)
- - [Mapping memory](@ref quick_start_mapping_memory)
- - \subpage custom_pools
- - \subpage defragmentation
- - \subpage statistics
- - \subpage resource_aliasing
- - \subpage linear_algorithm
- - \subpage virtual_allocator
- - \subpage configuration
- - [Custom CPU memory allocator](@ref custom_memory_allocator)
- - [Debug margins](@ref debug_margins)
- - \subpage general_considerations
- - [Thread safety](@ref general_considerations_thread_safety)
- - [Versioning and compatibility](@ref general_considerations_versioning_and_compatibility)
- - [Features not supported](@ref general_considerations_features_not_supported)
-
- \section main_see_also See also
- - [Product page on GPUOpen](https://gpuopen.com/gaming-product/d3d12-memory-allocator/)
- - [Source repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator)
- */
- // If using this library on a platform different than Windows PC or want to use different version of DXGI,
- // you should include D3D12-compatible headers before this library on your own and define this macro.
- #ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
- #include <d3d12.h>
- #include <dxgi1_4.h>
- #endif
- // Define this macro to 0 to disable usage of DXGI 1.4 (needed for IDXGIAdapter3 and query for memory budget).
- #ifndef D3D12MA_DXGI_1_4
- #ifdef __IDXGIAdapter3_INTERFACE_DEFINED__
- #define D3D12MA_DXGI_1_4 1
- #else
- #define D3D12MA_DXGI_1_4 0
- #endif
- #endif
- /*
- When defined to value other than 0, the library will try to use
- D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT or D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT
- for created textures when possible, which can save memory because some small textures
- may get their alignment 4K and their size a multiply of 4K instead of 64K.
- #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 0
- Disables small texture alignment.
- #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1
- Enables conservative algorithm that will use small alignment only for some textures
- that are surely known to support it.
- #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 2
- Enables query for small alignment to D3D12 (based on Microsoft sample) which will
- enable small alignment for more textures, but will also generate D3D Debug Layer
- error #721 on call to ID3D12Device::GetResourceAllocationInfo, which you should just
- ignore.
- */
- #ifndef D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
- #define D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT 1
- #endif
- /// \cond INTERNAL
- #define D3D12MA_CLASS_NO_COPY(className) \
- private: \
- className(const className&) = delete; \
- className(className&&) = delete; \
- className& operator=(const className&) = delete; \
- className& operator=(className&&) = delete;
- // To be used with MAKE_HRESULT to define custom error codes.
- #define FACILITY_D3D12MA 3542
- /*
- If providing your own implementation, you need to implement a subset of std::atomic.
- */
- #if !defined(D3D12MA_ATOMIC_UINT32) || !defined(D3D12MA_ATOMIC_UINT64)
- #include <atomic>
- #endif
- #ifndef D3D12MA_ATOMIC_UINT32
- #define D3D12MA_ATOMIC_UINT32 std::atomic<UINT>
- #endif
- #ifndef D3D12MA_ATOMIC_UINT64
- #define D3D12MA_ATOMIC_UINT64 std::atomic<UINT64>
- #endif
- #ifdef D3D12MA_EXPORTS
- #define D3D12MA_API __declspec(dllexport)
- #elif defined(D3D12MA_IMPORTS)
- #define D3D12MA_API __declspec(dllimport)
- #else
- #define D3D12MA_API
- #endif
- // Forward declaration if ID3D12ProtectedResourceSession is not defined inside the headers (older SDK, pre ID3D12Device4)
- struct ID3D12ProtectedResourceSession;
- // Define this enum even if SDK doesn't provide it, to simplify the API.
- #ifndef __ID3D12Device1_INTERFACE_DEFINED__
- typedef enum D3D12_RESIDENCY_PRIORITY
- {
- D3D12_RESIDENCY_PRIORITY_MINIMUM = 0x28000000,
- D3D12_RESIDENCY_PRIORITY_LOW = 0x50000000,
- D3D12_RESIDENCY_PRIORITY_NORMAL = 0x78000000,
- D3D12_RESIDENCY_PRIORITY_HIGH = 0xa0010000,
- D3D12_RESIDENCY_PRIORITY_MAXIMUM = 0xc8000000
- } D3D12_RESIDENCY_PRIORITY;
- #endif
- namespace D3D12MA
- {
- class D3D12MA_API IUnknownImpl : public IUnknown
- {
- public:
- virtual ~IUnknownImpl() = default;
- virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
- virtual ULONG STDMETHODCALLTYPE AddRef();
- virtual ULONG STDMETHODCALLTYPE Release();
- protected:
- virtual void ReleaseThis() { delete this; }
- private:
- D3D12MA_ATOMIC_UINT32 m_RefCount = {1};
- };
- } // namespace D3D12MA
- /// \endcond
- namespace D3D12MA
- {
- /// \cond INTERNAL
- class DefragmentationContextPimpl;
- class AllocatorPimpl;
- class PoolPimpl;
- class NormalBlock;
- class BlockVector;
- class CommittedAllocationList;
- class JsonWriter;
- class VirtualBlockPimpl;
- /// \endcond
- class Pool;
- class Allocator;
- struct Statistics;
- struct DetailedStatistics;
- struct TotalStatistics;
- /// \brief Unique identifier of single allocation done inside the memory heap.
- typedef UINT64 AllocHandle;
- /// Pointer to custom callback function that allocates CPU memory.
- using ALLOCATE_FUNC_PTR = void* (*)(size_t Size, size_t Alignment, void* pPrivateData);
- /**
- \brief Pointer to custom callback function that deallocates CPU memory.
- `pMemory = null` should be accepted and ignored.
- */
- using FREE_FUNC_PTR = void (*)(void* pMemory, void* pPrivateData);
- /// Custom callbacks to CPU memory allocation functions.
- struct ALLOCATION_CALLBACKS
- {
- /// %Allocation function.
- ALLOCATE_FUNC_PTR pAllocate;
- /// Dellocation function.
- FREE_FUNC_PTR pFree;
- /// Custom data that will be passed to allocation and deallocation functions as `pUserData` parameter.
- void* pPrivateData;
- };
- /// \brief Bit flags to be used with ALLOCATION_DESC::Flags.
- enum ALLOCATION_FLAGS
- {
- /// Zero
- ALLOCATION_FLAG_NONE = 0,
- /**
- Set this flag if the allocation should have its own dedicated memory allocation (committed resource with implicit heap).
-
- Use it for special, big resources, like fullscreen textures used as render targets.
- - When used with functions like D3D12MA::Allocator::CreateResource, it will use `ID3D12Device::CreateCommittedResource`,
- so the created allocation will contain a resource (D3D12MA::Allocation::GetResource() `!= NULL`) but will not have
- a heap (D3D12MA::Allocation::GetHeap() `== NULL`), as the heap is implicit.
- - When used with raw memory allocation like D3D12MA::Allocator::AllocateMemory, it will use `ID3D12Device::CreateHeap`,
- so the created allocation will contain a heap (D3D12MA::Allocation::GetHeap() `!= NULL`) and its offset will always be 0.
- */
- ALLOCATION_FLAG_COMMITTED = 0x1,
- /**
- Set this flag to only try to allocate from existing memory heaps and never create new such heap.
- If new allocation cannot be placed in any of the existing heaps, allocation
- fails with `E_OUTOFMEMORY` error.
- You should not use D3D12MA::ALLOCATION_FLAG_COMMITTED and
- D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.
- */
- ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2,
- /** Create allocation only if additional memory required for it, if any, won't exceed
- memory budget. Otherwise return `E_OUTOFMEMORY`.
- */
- ALLOCATION_FLAG_WITHIN_BUDGET = 0x4,
- /** Allocation will be created from upper stack in a double stack pool.
- This flag is only allowed for custom pools created with #POOL_FLAG_ALGORITHM_LINEAR flag.
- */
- ALLOCATION_FLAG_UPPER_ADDRESS = 0x8,
- /** Set this flag if the allocated memory will have aliasing resources.
-
- Use this when calling D3D12MA::Allocator::CreateResource() and similar to
- guarantee creation of explicit heap for desired allocation and prevent it from using `CreateCommittedResource`,
- so that new allocation object will always have `allocation->GetHeap() != NULL`.
- */
- ALLOCATION_FLAG_CAN_ALIAS = 0x10,
- /** Allocation strategy that chooses smallest possible free range for the allocation
- to minimize memory usage and fragmentation, possibly at the expense of allocation time.
- */
- ALLOCATION_FLAG_STRATEGY_MIN_MEMORY = 0x00010000,
- /** Allocation strategy that chooses first suitable free range for the allocation -
- not necessarily in terms of the smallest offset but the one that is easiest and fastest to find
- to minimize allocation time, possibly at the expense of allocation quality.
- */
- ALLOCATION_FLAG_STRATEGY_MIN_TIME = 0x00020000,
- /** Allocation strategy that chooses always the lowest offset in available space.
- This is not the most efficient strategy but achieves highly packed data.
- Used internally by defragmentation, not recomended in typical usage.
- */
- ALLOCATION_FLAG_STRATEGY_MIN_OFFSET = 0x0004000,
- /// Alias to #ALLOCATION_FLAG_STRATEGY_MIN_MEMORY.
- ALLOCATION_FLAG_STRATEGY_BEST_FIT = ALLOCATION_FLAG_STRATEGY_MIN_MEMORY,
- /// Alias to #ALLOCATION_FLAG_STRATEGY_MIN_TIME.
- ALLOCATION_FLAG_STRATEGY_FIRST_FIT = ALLOCATION_FLAG_STRATEGY_MIN_TIME,
- /// A bit mask to extract only `STRATEGY` bits from entire set of flags.
- ALLOCATION_FLAG_STRATEGY_MASK =
- ALLOCATION_FLAG_STRATEGY_MIN_MEMORY |
- ALLOCATION_FLAG_STRATEGY_MIN_TIME |
- ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
- };
- /// \brief Parameters of created D3D12MA::Allocation object. To be used with Allocator::CreateResource.
- struct ALLOCATION_DESC
- {
- /// Flags.
- ALLOCATION_FLAGS Flags;
- /** \brief The type of memory heap where the new allocation should be placed.
- It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
- When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
- */
- D3D12_HEAP_TYPE HeapType;
- /** \brief Additional heap flags to be used when allocating memory.
- In most cases it can be 0.
-
- - If you use D3D12MA::Allocator::CreateResource(), you don't need to care.
- Necessary flag `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`, `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
- or `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES` is added automatically.
- - If you use D3D12MA::Allocator::AllocateMemory(), you should specify one of those `ALLOW_ONLY` flags.
- Except when you validate that D3D12MA::Allocator::GetD3D12Options()`.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1` -
- then you can leave it 0.
- - You can specify additional flags if needed. Then the memory will always be allocated as
- separate block using `D3D12Device::CreateCommittedResource` or `CreateHeap`, not as part of an existing larget block.
- When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
- */
- D3D12_HEAP_FLAGS ExtraHeapFlags;
- /** \brief Custom pool to place the new resource in. Optional.
- When not NULL, the resource will be created inside specified custom pool.
- */
- Pool* CustomPool;
- /// Custom general-purpose pointer that will be stored in D3D12MA::Allocation.
- void* pPrivateData;
- };
- /** \brief Calculated statistics of memory usage e.g. in a specific memory heap type,
- memory segment group, custom pool, or total.
- These are fast to calculate.
- See functions: D3D12MA::Allocator::GetBudget(), D3D12MA::Pool::GetStatistics().
- */
- struct Statistics
- {
- /** \brief Number of D3D12 memory blocks allocated - `ID3D12Heap` objects and committed resources.
- */
- UINT BlockCount;
- /** \brief Number of D3D12MA::Allocation objects allocated.
- Committed allocations have their own blocks, so each one adds 1 to `AllocationCount` as well as `BlockCount`.
- */
- UINT AllocationCount;
- /** \brief Number of bytes allocated in memory blocks.
- */
- UINT64 BlockBytes;
- /** \brief Total number of bytes occupied by all D3D12MA::Allocation objects.
- Always less or equal than `BlockBytes`.
- Difference `(BlockBytes - AllocationBytes)` is the amount of memory allocated from D3D12
- but unused by any D3D12MA::Allocation.
- */
- UINT64 AllocationBytes;
- };
- /** \brief More detailed statistics than D3D12MA::Statistics.
- These are slower to calculate. Use for debugging purposes.
- See functions: D3D12MA::Allocator::CalculateStatistics(), D3D12MA::Pool::CalculateStatistics().
- Averages are not provided because they can be easily calculated as:
- \code
- UINT64 AllocationSizeAvg = DetailedStats.Statistics.AllocationBytes / detailedStats.Statistics.AllocationCount;
- UINT64 UnusedBytes = DetailedStats.Statistics.BlockBytes - DetailedStats.Statistics.AllocationBytes;
- UINT64 UnusedRangeSizeAvg = UnusedBytes / DetailedStats.UnusedRangeCount;
- \endcode
- */
- struct DetailedStatistics
- {
- /// Basic statistics.
- Statistics Stats;
- /// Number of free ranges of memory between allocations.
- UINT UnusedRangeCount;
- /// Smallest allocation size. `UINT64_MAX` if there are 0 allocations.
- UINT64 AllocationSizeMin;
- /// Largest allocation size. 0 if there are 0 allocations.
- UINT64 AllocationSizeMax;
- /// Smallest empty range size. `UINT64_MAX` if there are 0 empty ranges.
- UINT64 UnusedRangeSizeMin;
- /// Largest empty range size. 0 if there are 0 empty ranges.
- UINT64 UnusedRangeSizeMax;
- };
- /** \brief General statistics from current state of the allocator -
- total memory usage across all memory heaps and segments.
- These are slower to calculate. Use for debugging purposes.
- See function D3D12MA::Allocator::CalculateStatistics().
- */
- struct TotalStatistics
- {
- /** \brief One element for each type of heap located at the following indices:
- - 0 = `D3D12_HEAP_TYPE_DEFAULT`
- - 1 = `D3D12_HEAP_TYPE_UPLOAD`
- - 2 = `D3D12_HEAP_TYPE_READBACK`
- - 3 = `D3D12_HEAP_TYPE_CUSTOM`
- */
- DetailedStatistics HeapType[4];
- /** \brief One element for each memory segment group located at the following indices:
- - 0 = `DXGI_MEMORY_SEGMENT_GROUP_LOCAL`
- - 1 = `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`
- Meaning of these segment groups is:
- - When `IsUMA() == FALSE` (discrete graphics card):
- - `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` (index 0) represents GPU memory
- (resources allocated in `D3D12_HEAP_TYPE_DEFAULT` or `D3D12_MEMORY_POOL_L1`).
- - `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL` (index 1) represents system memory
- (resources allocated in `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`, or `D3D12_MEMORY_POOL_L0`).
- - When `IsUMA() == TRUE` (integrated graphics chip):
- - `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` = (index 0) represents memory shared for all the resources.
- - `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL` = (index 1) is unused and always 0.
- */
- DetailedStatistics MemorySegmentGroup[2];
- /// Total statistics from all memory allocated from D3D12.
- DetailedStatistics Total;
- };
- /** \brief %Statistics of current memory usage and available budget for a specific memory segment group.
- These are fast to calculate. See function D3D12MA::Allocator::GetBudget().
- */
- struct Budget
- {
- /** \brief %Statistics fetched from the library.
- */
- Statistics Stats;
- /** \brief Estimated current memory usage of the program.
- Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if possible.
- It might be different than `BlockBytes` (usually higher) due to additional implicit objects
- also occupying the memory, like swapchain, pipeline state objects, descriptor heaps, command lists, or
- heaps and resources allocated outside of this library, if any.
- */
- UINT64 UsageBytes;
- /** \brief Estimated amount of memory available to the program.
- Fetched from system using `IDXGIAdapter3::QueryVideoMemoryInfo` if possible.
- It might be different (most probably smaller) than memory capacity returned
- by D3D12MA::Allocator::GetMemoryCapacity() due to factors
- external to the program, decided by the operating system.
- Difference `BudgetBytes - UsageBytes` is the amount of additional memory that can probably
- be allocated without problems. Exceeding the budget may result in various problems.
- */
- UINT64 BudgetBytes;
- };
- /// \brief Represents single memory allocation done inside VirtualBlock.
- struct D3D12MA_API VirtualAllocation
- {
- /// \brief Unique idenitfier of current allocation. 0 means null/invalid.
- AllocHandle AllocHandle;
- };
- /** \brief Represents single memory allocation.
- It may be either implicit memory heap dedicated to a single resource or a
- specific region of a bigger heap plus unique offset.
- To create such object, fill structure D3D12MA::ALLOCATION_DESC and call function
- Allocator::CreateResource.
- The object remembers size and some other information.
- To retrieve this information, use methods of this class.
- The object also remembers `ID3D12Resource` and "owns" a reference to it,
- so it calls `%Release()` on the resource when destroyed.
- */
- class D3D12MA_API Allocation : public IUnknownImpl
- {
- public:
- /** \brief Returns offset in bytes from the start of memory heap.
- You usually don't need to use this offset. If you create a buffer or a texture together with the allocation using function
- D3D12MA::Allocator::CreateResource, functions that operate on that resource refer to the beginning of the resource,
- not entire memory heap.
- If the Allocation represents committed resource with implicit heap, returns 0.
- */
- UINT64 GetOffset() const;
- /// Returns alignment that resource was created with.
- UINT64 GetAlignment() const { return m_Alignment; }
- /** \brief Returns size in bytes of the allocation.
- - If you created a buffer or a texture together with the allocation using function D3D12MA::Allocator::CreateResource,
- this is the size of the resource returned by `ID3D12Device::GetResourceAllocationInfo`.
- - For allocations made out of bigger memory blocks, this also is the size of the memory region assigned exclusively to this allocation.
- - For resources created as committed, this value may not be accurate. DirectX implementation may optimize memory usage internally
- so that you may even observe regions of `ID3D12Resource::GetGPUVirtualAddress()` + Allocation::GetSize() to overlap in memory and still work correctly.
- */
- UINT64 GetSize() const { return m_Size; }
- /** \brief Returns D3D12 resource associated with this object.
- Calling this method doesn't increment resource's reference counter.
- */
- ID3D12Resource* GetResource() const { return m_Resource; }
- /// Releases the resource currently pointed by the allocation (if any), sets it to new one, incrementing its reference counter (if not null).
- void SetResource(ID3D12Resource* pResource);
- /** \brief Returns memory heap that the resource is created in.
- If the Allocation represents committed resource with implicit heap, returns NULL.
- */
- ID3D12Heap* GetHeap() const;
- /// Changes custom pointer for an allocation to a new value.
- void SetPrivateData(void* pPrivateData) { m_pPrivateData = pPrivateData; }
- /// Get custom pointer associated with the allocation.
- void* GetPrivateData() const { return m_pPrivateData; }
- /** \brief Associates a name with the allocation object. This name is for use in debug diagnostics and tools.
- Internal copy of the string is made, so the memory pointed by the argument can be
- changed of freed immediately after this call.
- `Name` can be null.
- */
- void SetName(LPCWSTR Name);
- /** \brief Returns the name associated with the allocation object.
- Returned string points to an internal copy.
- If no name was associated with the allocation, returns null.
- */
- LPCWSTR GetName() const { return m_Name; }
- /** \brief Returns `TRUE` if the memory of the allocation was filled with zeros when the allocation was created.
- Returns `TRUE` only if the allocator is sure that the entire memory where the
- allocation was created was filled with zeros at the moment the allocation was made.
-
- Returns `FALSE` if the memory could potentially contain garbage data.
- If it's a render-target or depth-stencil texture, it then needs proper
- initialization with `ClearRenderTargetView`, `ClearDepthStencilView`, `DiscardResource`,
- or a copy operation, as described on page
- "ID3D12Device::CreatePlacedResource method - Notes on the required resource initialization" in Microsoft documentation.
- Please note that rendering a fullscreen triangle or quad to the texture as
- a render target is not a proper way of initialization!
- See also articles:
- - "Coming to DirectX 12: More control over memory allocation" on DirectX Developer Blog
- - ["Initializing DX12 Textures After Allocation and Aliasing"](https://asawicki.info/news_1724_initializing_dx12_textures_after_allocation_and_aliasing).
- */
- BOOL WasZeroInitialized() const { return m_PackedData.WasZeroInitialized(); }
- protected:
- void ReleaseThis() override;
- private:
- friend class AllocatorPimpl;
- friend class BlockVector;
- friend class CommittedAllocationList;
- friend class JsonWriter;
- friend class BlockMetadata_Linear;
- friend class DefragmentationContextPimpl;
- friend struct CommittedAllocationListItemTraits;
- template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
- template<typename T> friend class PoolAllocator;
- enum Type
- {
- TYPE_COMMITTED,
- TYPE_PLACED,
- TYPE_HEAP,
- TYPE_COUNT
- };
- AllocatorPimpl* m_Allocator;
- UINT64 m_Size;
- UINT64 m_Alignment;
- ID3D12Resource* m_Resource;
- void* m_pPrivateData;
- wchar_t* m_Name;
- union
- {
- struct
- {
- CommittedAllocationList* list;
- Allocation* prev;
- Allocation* next;
- } m_Committed;
- struct
- {
- AllocHandle allocHandle;
- NormalBlock* block;
- } m_Placed;
- struct
- {
- // Beginning must be compatible with m_Committed.
- CommittedAllocationList* list;
- Allocation* prev;
- Allocation* next;
- ID3D12Heap* heap;
- } m_Heap;
- };
- struct PackedData
- {
- public:
- PackedData() :
- m_Type(0), m_ResourceDimension(0), m_ResourceFlags(0), m_TextureLayout(0), m_WasZeroInitialized(0) { }
- Type GetType() const { return (Type)m_Type; }
- D3D12_RESOURCE_DIMENSION GetResourceDimension() const { return (D3D12_RESOURCE_DIMENSION)m_ResourceDimension; }
- D3D12_RESOURCE_FLAGS GetResourceFlags() const { return (D3D12_RESOURCE_FLAGS)m_ResourceFlags; }
- D3D12_TEXTURE_LAYOUT GetTextureLayout() const { return (D3D12_TEXTURE_LAYOUT)m_TextureLayout; }
- BOOL WasZeroInitialized() const { return (BOOL)m_WasZeroInitialized; }
- void SetType(Type type);
- void SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension);
- void SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags);
- void SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout);
- void SetWasZeroInitialized(BOOL wasZeroInitialized) { m_WasZeroInitialized = wasZeroInitialized ? 1 : 0; }
- private:
- UINT m_Type : 2; // enum Type
- UINT m_ResourceDimension : 3; // enum D3D12_RESOURCE_DIMENSION
- UINT m_ResourceFlags : 24; // flags D3D12_RESOURCE_FLAGS
- UINT m_TextureLayout : 9; // enum D3D12_TEXTURE_LAYOUT
- UINT m_WasZeroInitialized : 1; // BOOL
- } m_PackedData;
- Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment, BOOL wasZeroInitialized);
- // Nothing here, everything already done in Release.
- virtual ~Allocation() = default;
- void InitCommitted(CommittedAllocationList* list);
- void InitPlaced(AllocHandle allocHandle, NormalBlock* block);
- void InitHeap(CommittedAllocationList* list, ID3D12Heap* heap);
- void SwapBlockAllocation(Allocation* allocation);
- // If the Allocation represents committed resource with implicit heap, returns UINT64_MAX.
- AllocHandle GetAllocHandle() const;
- NormalBlock* GetBlock();
- template<typename D3D12_RESOURCE_DESC_T>
- void SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc);
- void FreeName();
- D3D12MA_CLASS_NO_COPY(Allocation)
- };
- /// Flags to be passed as DEFRAGMENTATION_DESC::Flags.
- enum DEFRAGMENTATION_FLAGS
- {
- /** Use simple but fast algorithm for defragmentation.
- May not achieve best results but will require least time to compute and least allocations to copy.
- */
- DEFRAGMENTATION_FLAG_ALGORITHM_FAST = 0x1,
- /** Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified.
- Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved.
- */
- DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED = 0x2,
- /** Perform full defragmentation of memory.
- Can result in notably more time to compute and allocations to copy, but will achieve best memory packing.
- */
- DEFRAGMENTATION_FLAG_ALGORITHM_FULL = 0x4,
- /// A bit mask to extract only `ALGORITHM` bits from entire set of flags.
- DEFRAGMENTATION_FLAG_ALGORITHM_MASK =
- DEFRAGMENTATION_FLAG_ALGORITHM_FAST |
- DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED |
- DEFRAGMENTATION_FLAG_ALGORITHM_FULL
- };
- /** \brief Parameters for defragmentation.
- To be used with functions Allocator::BeginDefragmentation() and Pool::BeginDefragmentation().
- */
- struct DEFRAGMENTATION_DESC
- {
- /// Flags.
- DEFRAGMENTATION_FLAGS Flags;
- /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places.
- 0 means no limit.
- */
- UINT64 MaxBytesPerPass;
- /** \brief Maximum number of allocations that can be moved during single pass to a different place.
- 0 means no limit.
- */
- UINT32 MaxAllocationsPerPass;
- };
- /// Operation performed on single defragmentation move.
- enum DEFRAGMENTATION_MOVE_OPERATION
- {
- /** Resource has been recreated at `pDstTmpAllocation`, data has been copied, old resource has been destroyed.
- `pSrcAllocation` will be changed to point to the new place. This is the default value set by DefragmentationContext::BeginPass().
- */
- DEFRAGMENTATION_MOVE_OPERATION_COPY = 0,
- /// Set this value if you cannot move the allocation. New place reserved at `pDstTmpAllocation` will be freed. `pSrcAllocation` will remain unchanged.
- DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1,
- /// 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`.
- DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2,
- };
- /// Single move of an allocation to be done for defragmentation.
- struct DEFRAGMENTATION_MOVE
- {
- /** \brief Operation to be performed on the allocation by DefragmentationContext::EndPass().
- Default value is #DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.
- */
- DEFRAGMENTATION_MOVE_OPERATION Operation;
- /// %Allocation that should be moved.
- Allocation* pSrcAllocation;
- /** \brief Temporary allocation pointing to destination memory that will replace `pSrcAllocation`.
- Use it to retrieve new `ID3D12Heap` and offset to create new `ID3D12Resource` and then store it here via Allocation::SetResource().
- \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass,
- to be used for storing newly created resource. DefragmentationContext::EndPass() will destroy it and make `pSrcAllocation` point to this memory.
- */
- Allocation* pDstTmpAllocation;
- };
- /** \brief Parameters for incremental defragmentation steps.
- To be used with function DefragmentationContext::BeginPass().
- */
- struct DEFRAGMENTATION_PASS_MOVE_INFO
- {
- /// Number of elements in the `pMoves` array.
- UINT32 MoveCount;
- /** \brief Array of moves to be performed by the user in the current defragmentation pass.
- Pointer to an array of `MoveCount` elements, owned by %D3D12MA, created in DefragmentationContext::BeginPass(), destroyed in DefragmentationContext::EndPass().
- For each element, you should:
- 1. Create a new resource in the place pointed by `pMoves[i].pDstTmpAllocation->GetHeap()` + `pMoves[i].pDstTmpAllocation->GetOffset()`.
- 2. Store new resource in `pMoves[i].pDstTmpAllocation` by using Allocation::SetResource(). It will later replace old resource from `pMoves[i].pSrcAllocation`.
- 3. Copy data from the `pMoves[i].pSrcAllocation` e.g. using `D3D12GraphicsCommandList::CopyResource`.
- 4. Make sure these commands finished executing on the GPU.
- Only then you can finish defragmentation pass by calling DefragmentationContext::EndPass().
- After this call, the allocation will point to the new place in memory.
- Alternatively, if you cannot move specific allocation,
- you can set DEFRAGMENTATION_MOVE::Operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
- Alternatively, if you decide you want to completely remove the allocation,
- set DEFRAGMENTATION_MOVE::Operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY.
- Then, after DefragmentationContext::EndPass() the allocation will be released.
- */
- DEFRAGMENTATION_MOVE* pMoves;
- };
- /// %Statistics returned for defragmentation process by function DefragmentationContext::GetStats().
- struct DEFRAGMENTATION_STATS
- {
- /// Total number of bytes that have been copied while moving allocations to different places.
- UINT64 BytesMoved;
- /// Total number of bytes that have been released to the system by freeing empty heaps.
- UINT64 BytesFreed;
- /// Number of allocations that have been moved to different places.
- UINT32 AllocationsMoved;
- /// Number of empty `ID3D12Heap` objects that have been released to the system.
- UINT32 HeapsFreed;
- };
- /** \brief Represents defragmentation process in progress.
- You can create this object using Allocator::BeginDefragmentation (for default pools) or
- Pool::BeginDefragmentation (for a custom pool).
- */
- class D3D12MA_API DefragmentationContext : public IUnknownImpl
- {
- public:
- /** \brief Starts single defragmentation pass.
- \param[out] pPassInfo Computed informations for current pass.
- \returns
- - `S_OK` if no more moves are possible. Then you can omit call to DefragmentationContext::EndPass() and simply end whole defragmentation.
- - `S_FALSE` if there are pending moves returned in `pPassInfo`. You need to perform them, call DefragmentationContext::EndPass(),
- and then preferably try another pass with DefragmentationContext::BeginPass().
- */
- HRESULT BeginPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo);
- /** \brief Ends single defragmentation pass.
- \param pPassInfo Computed informations for current pass filled by DefragmentationContext::BeginPass() and possibly modified by you.
- \return Returns `S_OK` if no more moves are possible or `S_FALSE` if more defragmentations are possible.
- Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`.
- After this call:
- - %Allocation at `pPassInfo[i].pSrcAllocation` that had `pPassInfo[i].Operation ==` #DEFRAGMENTATION_MOVE_OPERATION_COPY
- (which is the default) will be pointing to the new destination place.
- - %Allocation at `pPassInfo[i].pSrcAllocation` that had `pPassInfo[i].operation ==` #DEFRAGMENTATION_MOVE_OPERATION_DESTROY
- will be released.
- If no more moves are possible you can end whole defragmentation.
- */
- HRESULT EndPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo);
- /** \brief Returns statistics of the defragmentation performed so far.
- */
- void GetStats(DEFRAGMENTATION_STATS* pStats);
- protected:
- void ReleaseThis() override;
- private:
- friend class Pool;
- friend class Allocator;
- template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
- DefragmentationContextPimpl* m_Pimpl;
- DefragmentationContext(AllocatorPimpl* allocator,
- const DEFRAGMENTATION_DESC& desc,
- BlockVector* poolVector);
- ~DefragmentationContext();
- D3D12MA_CLASS_NO_COPY(DefragmentationContext)
- };
- /// \brief Bit flags to be used with POOL_DESC::Flags.
- enum POOL_FLAGS
- {
- /// Zero
- POOL_FLAG_NONE = 0,
- /** \brief Enables alternative, linear allocation algorithm in this pool.
- Specify this flag to enable linear allocation algorithm, which always creates
- new allocations after last one and doesn't reuse space from allocations freed in
- between. It trades memory consumption for simplified algorithm and data
- structure, which has better performance and uses less memory for metadata.
- By using this flag, you can achieve behavior of free-at-once, stack,
- ring buffer, and double stack.
- For details, see documentation chapter \ref linear_algorithm.
- */
- POOL_FLAG_ALGORITHM_LINEAR = 0x1,
- /** \brief Optimization, allocate MSAA textures as committed resources always.
-
- Specify this flag to create MSAA textures with implicit heaps, as if they were created
- with flag D3D12MA::ALLOCATION_FLAG_COMMITTED. Usage of this flags enables pool to create its heaps
- on smaller alignment not suitable for MSAA textures.
- */
- POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x2,
- // Bit mask to extract only `ALGORITHM` bits from entire set of flags.
- POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_LINEAR
- };
- /// \brief Parameters of created D3D12MA::Pool object. To be used with D3D12MA::Allocator::CreatePool.
- struct POOL_DESC
- {
- /// Flags.
- POOL_FLAGS Flags;
- /** \brief The parameters of memory heap where allocations of this pool should be placed.
- In the simplest case, just fill it with zeros and set `Type` to one of: `D3D12_HEAP_TYPE_DEFAULT`,
- `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`. Additional parameters can be used e.g. to utilize UMA.
- */
- D3D12_HEAP_PROPERTIES HeapProperties;
- /** \brief Heap flags to be used when allocating heaps of this pool.
- It should contain one of these values, depending on type of resources you are going to create in this heap:
- `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
- `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
- `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
- Except if ResourceHeapTier = 2, then it may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
-
- You can specify additional flags if needed.
- */
- D3D12_HEAP_FLAGS HeapFlags;
- /** \brief Size of a single heap (memory block) to be allocated as part of this pool, in bytes. Optional.
- Specify nonzero to set explicit, constant size of memory blocks used by this pool.
- Leave 0 to use default and let the library manage block sizes automatically.
- Then sizes of particular blocks may vary.
- */
- UINT64 BlockSize;
- /** \brief Minimum number of heaps (memory blocks) to be always allocated in this pool, even if they stay empty. Optional.
- Set to 0 to have no preallocated blocks and allow the pool be completely empty.
- */
- UINT MinBlockCount;
- /** \brief Maximum number of heaps (memory blocks) that can be allocated in this pool. Optional.
- Set to 0 to use default, which is `UINT64_MAX`, which means no limit.
- Set to same value as D3D12MA::POOL_DESC::MinBlockCount to have fixed amount of memory allocated
- throughout whole lifetime of this pool.
- */
- UINT MaxBlockCount;
- /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0.
-
- Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two.
- */
- UINT64 MinAllocationAlignment;
- /** \brief Additional parameter allowing pool to create resources with passed protected session.
-
- If not null then all the heaps and committed resources will be created with this parameter.
- Valid only if ID3D12Device4 interface is present in current Windows SDK!
- */
- ID3D12ProtectedResourceSession* pProtectedSession;
- /** \brief Residency priority to be set for all allocations made in this pool. Optional.
-
- Set this parameter to one of the possible enum values e.g. `D3D12_RESIDENCY_PRIORITY_HIGH`
- to apply specific residency priority to all allocations made in this pool:
- `ID3D12Heap` memory blocks used to sub-allocate for placed resources, as well as
- committed resources or heaps created when D3D12MA::ALLOCATION_FLAG_COMMITTED is used.
- This can increase/decrease chance that the memory will be pushed out from VRAM
- to system RAM when the system runs out of memory, which is invisible to the developer
- using D3D12 API while it can degrade performance.
- Priority is set using function `ID3D12Device1::SetResidencyPriority`.
- It is performed only when `ID3D12Device1` interface is defined and successfully obtained.
- Otherwise, this parameter is ignored.
- This parameter is optional. If you set it to `D3D12_RESIDENCY_PRIORITY(0)`,
- residency priority will not be set for allocations made in this pool.
- There is no equivalent parameter for allocations made in default pools.
- If you want to set residency priority for such allocation, you need to do it manually:
- allocate with D3D12MA::ALLOCATION_FLAG_COMMITTED and call
- `ID3D12Device1::SetResidencyPriority`, passing `allocation->GetResource()`.
- */
- D3D12_RESIDENCY_PRIORITY ResidencyPriority;
- };
- /** \brief Custom memory pool
- Represents a separate set of heaps (memory blocks) that can be used to create
- D3D12MA::Allocation-s and resources in it. Usually there is no need to create custom
- pools - creating resources in default pool is sufficient.
- To create custom pool, fill D3D12MA::POOL_DESC and call D3D12MA::Allocator::CreatePool.
- */
- class D3D12MA_API Pool : public IUnknownImpl
- {
- public:
- /** \brief Returns copy of parameters of the pool.
- These are the same parameters as passed to D3D12MA::Allocator::CreatePool.
- */
- POOL_DESC GetDesc() const;
- /** \brief Retrieves basic statistics of the custom pool that are fast to calculate.
- \param[out] pStats %Statistics of the current pool.
- */
- void GetStatistics(Statistics* pStats);
- /** \brief Retrieves detailed statistics of the custom pool that are slower to calculate.
- \param[out] pStats %Statistics of the current pool.
- */
- void CalculateStatistics(DetailedStatistics* pStats);
- /** \brief Associates a name with the pool. This name is for use in debug diagnostics and tools.
- Internal copy of the string is made, so the memory pointed by the argument can be
- changed of freed immediately after this call.
- `Name` can be NULL.
- */
- void SetName(LPCWSTR Name);
- /** \brief Returns the name associated with the pool object.
- Returned string points to an internal copy.
- If no name was associated with the allocation, returns NULL.
- */
- LPCWSTR GetName() const;
- /** \brief Begins defragmentation process of the current pool.
- \param pDesc Structure filled with parameters of defragmentation.
- \param[out] ppContext Context object that will manage defragmentation.
- \returns
- - `S_OK` if defragmentation can begin.
- - `E_NOINTERFACE` if defragmentation is not supported.
- For more information about defragmentation, see documentation chapter:
- [Defragmentation](@ref defragmentation).
- */
- HRESULT BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext);
- protected:
- void ReleaseThis() override;
- private:
- friend class Allocator;
- friend class AllocatorPimpl;
- template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
- PoolPimpl* m_Pimpl;
- Pool(Allocator* allocator, const POOL_DESC &desc);
- ~Pool();
- D3D12MA_CLASS_NO_COPY(Pool)
- };
- /// \brief Bit flags to be used with ALLOCATOR_DESC::Flags.
- enum ALLOCATOR_FLAGS
- {
- /// Zero
- ALLOCATOR_FLAG_NONE = 0,
- /**
- Allocator and all objects created from it will not be synchronized internally,
- so you must guarantee they are used from only one thread at a time or
- synchronized by you.
- Using this flag may increase performance because internal mutexes are not used.
- */
- ALLOCATOR_FLAG_SINGLETHREADED = 0x1,
- /**
- Every allocation will have its own memory block.
- To be used for debugging purposes.
- */
- ALLOCATOR_FLAG_ALWAYS_COMMITTED = 0x2,
- /**
- Heaps created for the default pools will be created with flag `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED`,
- allowing for their memory to be not zeroed by the system if possible,
- which can speed up allocation.
- Only affects default pools.
- To use the flag with @ref custom_pools, you need to add it manually:
- \code
- poolDesc.heapFlags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
- \endcode
- Only avaiable if `ID3D12Device8` is present. Otherwise, the flag is ignored.
- */
- ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED = 0x4,
- /** \brief Optimization, allocate MSAA textures as committed resources always.
- Specify this flag to create MSAA textures with implicit heaps, as if they were created
- with flag D3D12MA::ALLOCATION_FLAG_COMMITTED. Usage of this flags enables all default pools
- to create its heaps on smaller alignment not suitable for MSAA textures.
- */
- ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x8,
- };
- /// \brief Parameters of created Allocator object. To be used with CreateAllocator().
- struct ALLOCATOR_DESC
- {
- /// Flags.
- ALLOCATOR_FLAGS Flags;
-
- /** Direct3D device object that the allocator should be attached to.
- Allocator is doing `AddRef`/`Release` on this object.
- */
- ID3D12Device* pDevice;
-
- /** \brief Preferred size of a single `ID3D12Heap` block to be allocated.
-
- Set to 0 to use default, which is currently 64 MiB.
- */
- UINT64 PreferredBlockSize;
-
- /** \brief Custom CPU memory allocation callbacks. Optional.
- Optional, can be null. When specified, will be used for all CPU-side memory allocations.
- */
- const ALLOCATION_CALLBACKS* pAllocationCallbacks;
- /** DXGI Adapter object that you use for D3D12 and this allocator.
- Allocator is doing `AddRef`/`Release` on this object.
- */
- IDXGIAdapter* pAdapter;
- };
- /**
- \brief Represents main object of this library initialized for particular `ID3D12Device`.
- Fill structure D3D12MA::ALLOCATOR_DESC and call function CreateAllocator() to create it.
- Call method `Release()` to destroy it.
- It is recommended to create just one object of this type per `ID3D12Device` object,
- right after Direct3D 12 is initialized and keep it alive until before Direct3D device is destroyed.
- */
- class D3D12MA_API Allocator : public IUnknownImpl
- {
- public:
- /// Returns cached options retrieved from D3D12 device.
- const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const;
- /** \brief Returns true if `D3D12_FEATURE_DATA_ARCHITECTURE1::UMA` was found to be true.
-
- For more information about how to use it, see articles in Microsoft Docs articles:
- - "UMA Optimizations: CPU Accessible Textures and Standard Swizzle"
- - "D3D12_FEATURE_DATA_ARCHITECTURE structure (d3d12.h)"
- - "ID3D12Device::GetCustomHeapProperties method (d3d12.h)"
- */
- BOOL IsUMA() const;
- /** \brief Returns true if `D3D12_FEATURE_DATA_ARCHITECTURE1::CacheCoherentUMA` was found to be true.
- For more information about how to use it, see articles in Microsoft Docs articles:
- - "UMA Optimizations: CPU Accessible Textures and Standard Swizzle"
- - "D3D12_FEATURE_DATA_ARCHITECTURE structure (d3d12.h)"
- - "ID3D12Device::GetCustomHeapProperties method (d3d12.h)"
- */
- BOOL IsCacheCoherentUMA() const;
- /** \brief Returns total amount of memory of specific segment group, in bytes.
-
- \param memorySegmentGroup use `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` or DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`.
- This information is taken from `DXGI_ADAPTER_DESC`.
- It is not recommended to use this number.
- You should preferably call GetBudget() and limit memory usage to D3D12MA::Budget::BudgetBytes instead.
- - When IsUMA() `== FALSE` (discrete graphics card):
- - `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)` returns the size of the video memory.
- - `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)` returns the size of the system memory available for D3D12 resources.
- - When IsUMA() `== TRUE` (integrated graphics chip):
- - `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL)` returns the size of the shared memory available for all D3D12 resources.
- All memory is considered "local".
- - `GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)` is not applicable and returns 0.
- */
- UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;
- /** \brief Allocates memory and creates a D3D12 resource (buffer or texture). This is the main allocation function.
- The function is similar to `ID3D12Device::CreateCommittedResource`, but it may
- really call `ID3D12Device::CreatePlacedResource` to assign part of a larger,
- existing memory heap to the new resource, which is the main purpose of this
- whole library.
- If `ppvResource` is null, you receive only `ppAllocation` object from this function.
- It holds pointer to `ID3D12Resource` that can be queried using function D3D12MA::Allocation::GetResource().
- Reference count of the resource object is 1.
- It is automatically destroyed when you destroy the allocation object.
- If `ppvResource` is not null, you receive pointer to the resource next to allocation object.
- Reference count of the resource object is then increased by calling `QueryInterface`, so you need to manually `Release` it
- along with the allocation.
- \param pAllocDesc Parameters of the allocation.
- \param pResourceDesc Description of created resource.
- \param InitialResourceState Initial resource state.
- \param pOptimizedClearValue Optional. Either null or optimized clear value.
- \param[out] ppAllocation Filled with pointer to new allocation object created.
- \param riidResource IID of a resource to be returned via `ppvResource`.
- \param[out] ppvResource Optional. If not null, filled with pointer to new resouce created.
- \note This function creates a new resource. Sub-allocation of parts of one large buffer,
- although recommended as a good practice, is out of scope of this library and could be implemented
- by the user as a higher-level logic on top of it, e.g. using the \ref virtual_allocator feature.
- */
- HRESULT CreateResource(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- /** \brief Similar to Allocator::CreateResource, but supports new structure `D3D12_RESOURCE_DESC1`.
-
- It internally uses `ID3D12Device8::CreateCommittedResource2` or `ID3D12Device8::CreatePlacedResource1`.
- To work correctly, `ID3D12Device8` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
- */
- HRESULT CreateResource2(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
- #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- /** \brief Similar to Allocator::CreateResource2, but there are initial layout instead of state and
- castable formats list
- It internally uses `ID3D12Device10::CreateCommittedResource3` or `ID3D12Device10::CreatePlacedResource2`.
- To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
- */
- HRESULT CreateResource3(const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_BARRIER_LAYOUT InitialLayout,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- UINT32 NumCastableFormats,
- DXGI_FORMAT* pCastableFormats,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
- #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- /** \brief Allocates memory without creating any resource placed in it.
- This function is similar to `ID3D12Device::CreateHeap`, but it may really assign
- part of a larger, existing heap to the allocation.
- `pAllocDesc->heapFlags` should contain one of these values, depending on type of resources you are going to create in this memory:
- `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
- `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
- `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
- Except if you validate that ResourceHeapTier = 2 - then `heapFlags`
- may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
- Additional flags in `heapFlags` are allowed as well.
- `pAllocInfo->SizeInBytes` must be multiply of 64KB.
- `pAllocInfo->Alignment` must be one of the legal values as described in documentation of `D3D12_HEAP_DESC`.
- If you use D3D12MA::ALLOCATION_FLAG_COMMITTED you will get a separate memory block -
- a heap that always has offset 0.
- */
- HRESULT AllocateMemory(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation);
- /** \brief Creates a new resource in place of an existing allocation. This is useful for memory aliasing.
- \param pAllocation Existing allocation indicating the memory where the new resource should be created.
- It can be created using D3D12MA::Allocator::CreateResource and already have a resource bound to it,
- or can be a raw memory allocated with D3D12MA::Allocator::AllocateMemory.
- It must not be created as committed so that `ID3D12Heap` is available and not implicit.
- \param AllocationLocalOffset Additional offset in bytes to be applied when allocating the resource.
- Local from the start of `pAllocation`, not the beginning of the whole `ID3D12Heap`!
- If the new resource should start from the beginning of the `pAllocation` it should be 0.
- \param pResourceDesc Description of the new resource to be created.
- \param InitialResourceState
- \param pOptimizedClearValue
- \param riidResource
- \param[out] ppvResource Returns pointer to the new resource.
- The resource is not bound with `pAllocation`.
- This pointer must not be null - you must get the resource pointer and `Release` it when no longer needed.
- Memory requirements of the new resource are checked for validation.
- If its size exceeds the end of `pAllocation` or required alignment is not fulfilled
- considering `pAllocation->GetOffset() + AllocationLocalOffset`, the function
- returns `E_INVALIDARG`.
- */
- HRESULT CreateAliasingResource(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- REFIID riidResource,
- void** ppvResource);
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- /** \brief Similar to Allocator::CreateAliasingResource, but supports new structure `D3D12_RESOURCE_DESC1`.
-
- It internally uses `ID3D12Device8::CreatePlacedResource1`.
- To work correctly, `ID3D12Device8` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
- */
- HRESULT CreateAliasingResource1(Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- REFIID riidResource,
- void** ppvResource);
- #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- /** \brief Similar to Allocator::CreateAliasingResource1, but there are initial layout instead of state and
- castable formats list
- It internally uses `ID3D12Device10::CreatePlacedResource2`.
- To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned.
- */
- HRESULT CreateAliasingResource2(Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_BARRIER_LAYOUT InitialLayout,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- UINT32 NumCastableFormats,
- DXGI_FORMAT* pCastableFormats,
- REFIID riidResource,
- void** ppvResource);
- #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- /** \brief Creates custom pool.
- */
- HRESULT CreatePool(
- const POOL_DESC* pPoolDesc,
- Pool** ppPool);
- /** \brief Sets the index of the current frame.
- This function is used to set the frame index in the allocator when a new game frame begins.
- */
- void SetCurrentFrameIndex(UINT frameIndex);
- /** \brief Retrieves information about current memory usage and budget.
- \param[out] pLocalBudget Optional, can be null.
- \param[out] pNonLocalBudget Optional, can be null.
- - When IsUMA() `== FALSE` (discrete graphics card):
- - `pLocalBudget` returns the budget of the video memory.
- - `pNonLocalBudget` returns the budget of the system memory available for D3D12 resources.
- - When IsUMA() `== TRUE` (integrated graphics chip):
- - `pLocalBudget` returns the budget of the shared memory available for all D3D12 resources.
- All memory is considered "local".
- - `pNonLocalBudget` is not applicable and returns zeros.
- This function is called "get" not "calculate" because it is very fast, suitable to be called
- every frame or every allocation. For more detailed statistics use CalculateStatistics().
- Note that when using allocator from multiple threads, returned information may immediately
- become outdated.
- */
- void GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget);
- /** \brief Retrieves statistics from current state of the allocator.
- This function is called "calculate" not "get" because it has to traverse all
- internal data structures, so it may be quite slow. Use it for debugging purposes.
- For faster but more brief statistics suitable to be called every frame or every allocation,
- use GetBudget().
- Note that when using allocator from multiple threads, returned information may immediately
- become outdated.
- */
- void CalculateStatistics(TotalStatistics* pStats);
- /** \brief Builds and returns statistics as a string in JSON format.
- *
- @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
- @param DetailedMap `TRUE` to include full list of allocations (can make the string quite long), `FALSE` to only return statistics.
- */
- void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const;
- /// Frees memory of a string returned from Allocator::BuildStatsString.
- void FreeStatsString(WCHAR* pStatsString) const;
- /** \brief Begins defragmentation process of the default pools.
- \param pDesc Structure filled with parameters of defragmentation.
- \param[out] ppContext Context object that will manage defragmentation.
- For more information about defragmentation, see documentation chapter:
- [Defragmentation](@ref defragmentation).
- */
- void BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext);
- protected:
- void ReleaseThis() override;
- private:
- friend D3D12MA_API HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);
- template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
- friend class DefragmentationContext;
- friend class Pool;
- Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
- ~Allocator();
-
- AllocatorPimpl* m_Pimpl;
-
- D3D12MA_CLASS_NO_COPY(Allocator)
- };
- /// \brief Bit flags to be used with VIRTUAL_BLOCK_DESC::Flags.
- enum VIRTUAL_BLOCK_FLAGS
- {
- /// Zero
- VIRTUAL_BLOCK_FLAG_NONE = 0,
- /** \brief Enables alternative, linear allocation algorithm in this virtual block.
- Specify this flag to enable linear allocation algorithm, which always creates
- new allocations after last one and doesn't reuse space from allocations freed in
- between. It trades memory consumption for simplified algorithm and data
- structure, which has better performance and uses less memory for metadata.
- By using this flag, you can achieve behavior of free-at-once, stack,
- ring buffer, and double stack.
- For details, see documentation chapter \ref linear_algorithm.
- */
- VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR = POOL_FLAG_ALGORITHM_LINEAR,
- // Bit mask to extract only `ALGORITHM` bits from entire set of flags.
- VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_MASK
- };
- /// Parameters of created D3D12MA::VirtualBlock object to be passed to CreateVirtualBlock().
- struct VIRTUAL_BLOCK_DESC
- {
- /// Flags.
- VIRTUAL_BLOCK_FLAGS Flags;
- /** \brief Total size of the block.
- Sizes can be expressed in bytes or any units you want as long as you are consistent in using them.
- For example, if you allocate from some array of structures, 1 can mean single instance of entire structure.
- */
- UINT64 Size;
- /** \brief Custom CPU memory allocation callbacks. Optional.
- Optional, can be null. When specified, will be used for all CPU-side memory allocations.
- */
- const ALLOCATION_CALLBACKS* pAllocationCallbacks;
- };
- /// \brief Bit flags to be used with VIRTUAL_ALLOCATION_DESC::Flags.
- enum VIRTUAL_ALLOCATION_FLAGS
- {
- /// Zero
- VIRTUAL_ALLOCATION_FLAG_NONE = 0,
- /** \brief Allocation will be created from upper stack in a double stack pool.
- This flag is only allowed for virtual blocks created with #VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR flag.
- */
- VIRTUAL_ALLOCATION_FLAG_UPPER_ADDRESS = ALLOCATION_FLAG_UPPER_ADDRESS,
- /// Allocation strategy that tries to minimize memory usage.
- VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_MEMORY = ALLOCATION_FLAG_STRATEGY_MIN_MEMORY,
- /// Allocation strategy that tries to minimize allocation time.
- VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_TIME = ALLOCATION_FLAG_STRATEGY_MIN_TIME,
- /** \brief Allocation strategy that chooses always the lowest offset in available space.
- This is not the most efficient strategy but achieves highly packed data.
- */
- VIRTUAL_ALLOCATION_FLAG_STRATEGY_MIN_OFFSET = ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
- /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags.
- These strategy flags are binary compatible with equivalent flags in #ALLOCATION_FLAGS.
- */
- VIRTUAL_ALLOCATION_FLAG_STRATEGY_MASK = ALLOCATION_FLAG_STRATEGY_MASK,
- };
- /// Parameters of created virtual allocation to be passed to VirtualBlock::Allocate().
- struct VIRTUAL_ALLOCATION_DESC
- {
- /// Flags.
- VIRTUAL_ALLOCATION_FLAGS Flags;
- /** \brief Size of the allocation.
-
- Cannot be zero.
- */
- UINT64 Size;
- /** \brief Required alignment of the allocation.
-
- 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.
- */
- UINT64 Alignment;
- /** \brief Custom pointer to be associated with the allocation.
- It can be fetched or changed later.
- */
- void* pPrivateData;
- };
- /// Parameters of an existing virtual allocation, returned by VirtualBlock::GetAllocationInfo().
- struct VIRTUAL_ALLOCATION_INFO
- {
- /// \brief Offset of the allocation.
- UINT64 Offset;
- /** \brief Size of the allocation.
- Same value as passed in VIRTUAL_ALLOCATION_DESC::Size.
- */
- UINT64 Size;
- /** \brief Custom pointer associated with the allocation.
- Same value as passed in VIRTUAL_ALLOCATION_DESC::pPrivateData or VirtualBlock::SetAllocationPrivateData().
- */
- void* pPrivateData;
- };
- /** \brief Represents pure allocation algorithm and a data structure with allocations in some memory block, without actually allocating any GPU memory.
- This class allows to use the core algorithm of the library custom allocations e.g. CPU memory or
- sub-allocation regions inside a single GPU buffer.
- To create this object, fill in D3D12MA::VIRTUAL_BLOCK_DESC and call CreateVirtualBlock().
- To destroy it, call its method `VirtualBlock::Release()`.
- You need to free all the allocations within this block or call Clear() before destroying it.
- This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally.
- */
- class D3D12MA_API VirtualBlock : public IUnknownImpl
- {
- public:
- /** \brief Returns true if the block is empty - contains 0 allocations.
- */
- BOOL IsEmpty() const;
- /** \brief Returns information about an allocation - its offset, size and custom pointer.
- */
- void GetAllocationInfo(VirtualAllocation allocation, VIRTUAL_ALLOCATION_INFO* pInfo) const;
- /** \brief Creates new allocation.
- \param pDesc
- \param[out] pAllocation Unique indentifier of the new allocation within single block.
- \param[out] pOffset Returned offset of the new allocation. Optional, can be null.
- \return `S_OK` if allocation succeeded, `E_OUTOFMEMORY` if it failed.
- If the allocation failed, `pAllocation->AllocHandle` is set to 0 and `pOffset`, if not null, is set to `UINT64_MAX`.
- */
- HRESULT Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, VirtualAllocation* pAllocation, UINT64* pOffset);
- /** \brief Frees the allocation.
-
- Calling this function with `allocation.AllocHandle == 0` is correct and does nothing.
- */
- void FreeAllocation(VirtualAllocation allocation);
- /** \brief Frees all the allocations.
- */
- void Clear();
- /** \brief Changes custom pointer for an allocation to a new value.
- */
- void SetAllocationPrivateData(VirtualAllocation allocation, void* pPrivateData);
- /** \brief Retrieves basic statistics of the virtual block that are fast to calculate.
- \param[out] pStats %Statistics of the virtual block.
- */
- void GetStatistics(Statistics* pStats) const;
- /** \brief Retrieves detailed statistics of the virtual block that are slower to calculate.
- \param[out] pStats %Statistics of the virtual block.
- */
- void CalculateStatistics(DetailedStatistics* pStats) const;
- /** \brief Builds and returns statistics as a string in JSON format, including the list of allocations with their parameters.
- @param[out] ppStatsString Must be freed using VirtualBlock::FreeStatsString.
- */
- void BuildStatsString(WCHAR** ppStatsString) const;
- /** \brief Frees memory of a string returned from VirtualBlock::BuildStatsString.
- */
- void FreeStatsString(WCHAR* pStatsString) const;
-
- protected:
- void ReleaseThis() override;
- private:
- friend D3D12MA_API HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC*, VirtualBlock**);
- template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
- VirtualBlockPimpl* m_Pimpl;
- VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
- ~VirtualBlock();
- D3D12MA_CLASS_NO_COPY(VirtualBlock)
- };
- /** \brief Creates new main D3D12MA::Allocator object and returns it through `ppAllocator`.
- You normally only need to call it once and keep a single Allocator object for your `ID3D12Device`.
- */
- D3D12MA_API HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator);
- /** \brief Creates new D3D12MA::VirtualBlock object and returns it through `ppVirtualBlock`.
- Note you don't need to create D3D12MA::Allocator to use virtual blocks.
- */
- D3D12MA_API HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock);
- } // namespace D3D12MA
- /// \cond INTERNAL
- DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATION_FLAGS);
- DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::DEFRAGMENTATION_FLAGS);
- DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::ALLOCATOR_FLAGS);
- DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::POOL_FLAGS);
- DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_BLOCK_FLAGS);
- DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_ALLOCATION_FLAGS);
- /// \endcond
- /**
- \page quick_start Quick start
- \section quick_start_project_setup Project setup and initialization
- This is a small, standalone C++ library. It consists of a pair of 2 files:
- "D3D12MemAlloc.h" header file with public interface and "D3D12MemAlloc.cpp" with
- internal implementation. The only external dependencies are WinAPI, Direct3D 12,
- and parts of C/C++ standard library (but STL containers, exceptions, or RTTI are
- not used).
- The library is developed and tested using Microsoft Visual Studio 2019, but it
- should work with other compilers as well. It is designed for 64-bit code.
- To use the library in your project:
- (1.) Copy files `D3D12MemAlloc.cpp`, `%D3D12MemAlloc.h` to your project.
- (2.) Make `D3D12MemAlloc.cpp` compiling as part of the project, as C++ code.
- (3.) Include library header in each CPP file that needs to use the library.
- \code
- #include "D3D12MemAlloc.h"
- \endcode
- (4.) Right after you created `ID3D12Device`, fill D3D12MA::ALLOCATOR_DESC
- structure and call function D3D12MA::CreateAllocator to create the main
- D3D12MA::Allocator object.
- Please note that all symbols of the library are declared inside #D3D12MA namespace.
- \code
- IDXGIAdapter* adapter = (...)
- ID3D12Device* device = (...)
- D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
- allocatorDesc.pDevice = device;
- allocatorDesc.pAdapter = adapter;
- D3D12MA::Allocator* allocator;
- HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
- \endcode
- (5.) Right before destroying the D3D12 device, destroy the allocator object.
- Objects of this library must be destroyed by calling `Release` method.
- They are somewhat compatible with COM: they implement `IUnknown` interface with its virtual methods: `AddRef`, `Release`, `QueryInterface`,
- and they are reference-counted internally.
- You can use smart pointers designed for COM with objects of this library - e.g. `CComPtr` or `Microsoft::WRL::ComPtr`.
- The reference counter is thread-safe.
- `QueryInterface` method supports only `IUnknown`, as classes of this library don't define their own GUIDs.
- \code
- allocator->Release();
- \endcode
- \section quick_start_creating_resources Creating resources
- To use the library for creating resources (textures and buffers), call method
- D3D12MA::Allocator::CreateResource in the place where you would previously call
- `ID3D12Device::CreateCommittedResource`.
- The function has similar syntax, but it expects structure D3D12MA::ALLOCATION_DESC
- to be passed along with `D3D12_RESOURCE_DESC` and other parameters for created
- resource. This structure describes parameters of the desired memory allocation,
- including choice of `D3D12_HEAP_TYPE`.
- The function returns a new object of type D3D12MA::Allocation.
- It represents allocated memory and can be queried for size, offset, `ID3D12Heap`.
- It also holds a reference to the `ID3D12Resource`, which can be accessed by calling D3D12MA::Allocation::GetResource().
- \code
- D3D12_RESOURCE_DESC resourceDesc = {};
- resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
- resourceDesc.Alignment = 0;
- resourceDesc.Width = 1024;
- resourceDesc.Height = 1024;
- resourceDesc.DepthOrArraySize = 1;
- resourceDesc.MipLevels = 1;
- resourceDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- resourceDesc.SampleDesc.Count = 1;
- resourceDesc.SampleDesc.Quality = 0;
- resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
- resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
- D3D12MA::ALLOCATION_DESC allocationDesc = {};
- allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
- D3D12MA::Allocation* allocation;
- HRESULT hr = allocator->CreateResource(
- &allocationDesc,
- &resourceDesc,
- D3D12_RESOURCE_STATE_COPY_DEST,
- NULL,
- &allocation,
- IID_NULL, NULL);
- // Use allocation->GetResource()...
- \endcode
- You need to release the allocation object when no longer needed.
- This will also release the D3D12 resource.
- \code
- allocation->Release();
- \endcode
- The advantage of using the allocator instead of creating committed resource, and
- the main purpose of this library, is that it can decide to allocate bigger memory
- heap internally using `ID3D12Device::CreateHeap` and place multiple resources in
- it, at different offsets, using `ID3D12Device::CreatePlacedResource`. The library
- manages its own collection of allocated memory blocks (heaps) and remembers which
- parts of them are occupied and which parts are free to be used for new resources.
- It is important to remember that resources created as placed don't have their memory
- initialized to zeros, but may contain garbage data, so they need to be fully initialized
- before usage, e.g. using Clear (`ClearRenderTargetView`), Discard (`DiscardResource`),
- or copy (`CopyResource`).
- The library also automatically handles resource heap tier.
- When `D3D12_FEATURE_DATA_D3D12_OPTIONS::ResourceHeapTier` equals `D3D12_RESOURCE_HEAP_TIER_1`,
- resources of 3 types: buffers, textures that are render targets or depth-stencil,
- and other textures must be kept in separate heaps. When `D3D12_RESOURCE_HEAP_TIER_2`,
- they can be kept together. By using this library, you don't need to handle this
- manually.
- \section quick_start_resource_reference_counting Resource reference counting
- `ID3D12Resource` and other interfaces of Direct3D 12 use COM, so they are reference-counted.
- Objects of this library are reference-counted as well.
- An object of type D3D12MA::Allocation remembers the resource (buffer or texture)
- that was created together with this memory allocation
- and holds a reference to the `ID3D12Resource` object.
- (Note this is a difference to Vulkan Memory Allocator, where a `VmaAllocation` object has no connection
- with the buffer or image that was created with it.)
- Thus, it is important to manage the resource reference counter properly.
- <b>The simplest use case</b> is shown in the code snippet above.
- When only D3D12MA::Allocation object is obtained from a function call like D3D12MA::Allocator::CreateResource,
- it remembers the `ID3D12Resource` that was created with it and holds a reference to it.
- The resource can be obtained by calling `allocation->GetResource()`, which doesn't increment the resource
- reference counter.
- Calling `allocation->Release()` will decrease the resource reference counter, which is = 1 in this case,
- so the resource will be released.
- <b>Second option</b> is to retrieve a pointer to the resource along with D3D12MA::Allocation.
- Last parameters of the resource creation function can be used for this purpose.
- \code
- D3D12MA::Allocation* allocation;
- ID3D12Resource* resource;
- HRESULT hr = allocator->CreateResource(
- &allocationDesc,
- &resourceDesc,
- D3D12_RESOURCE_STATE_COPY_DEST,
- NULL,
- &allocation,
- IID_PPV_ARGS(&resource));
- // Use resource...
- \endcode
- In this case, returned pointer `resource` is equal to `allocation->GetResource()`,
- but the creation function additionally increases resource reference counter for the purpose of returning it from this call
- (it actually calls `QueryInterface` internally), so the resource will have the counter = 2.
- The resource then need to be released along with the allocation, in this particular order,
- to make sure the resource is destroyed before its memory heap can potentially be freed.
- \code
- resource->Release();
- allocation->Release();
- \endcode
- <b>More advanced use cases</b> are possible when we consider that an D3D12MA::Allocation object can just hold
- a reference to any resource.
- It can be changed by calling D3D12MA::Allocation::SetResource. This function
- releases the old resource and calls `AddRef` on the new one.
- Special care must be taken when performing <b>defragmentation</b>.
- The new resource created at the destination place should be set as `pass.pMoves[i].pDstTmpAllocation->SetResource(newRes)`,
- but it is moved to the source allocation at end of the defragmentation pass,
- while the old resource accessible through `pass.pMoves[i].pSrcAllocation->GetResource()` is then released.
- For more information, see documentation chapter \ref defragmentation.
- \section quick_start_mapping_memory Mapping memory
- The process of getting regular CPU-side pointer to the memory of a resource in
- Direct3D is called "mapping". There are rules and restrictions to this process,
- as described in D3D12 documentation of `ID3D12Resource::Map` method.
- Mapping happens on the level of particular resources, not entire memory heaps,
- and so it is out of scope of this library. Just as the documentation of the `Map` function says:
- - Returned pointer refers to data of particular subresource, not entire memory heap.
- - You can map same resource multiple times. It is ref-counted internally.
- - Mapping is thread-safe.
- - Unmapping is not required before resource destruction.
- - Unmapping may not be required before using written data - some heap types on
- some platforms support resources persistently mapped.
- When using this library, you can map and use your resources normally without
- considering whether they are created as committed resources or placed resources in one large heap.
- Example for buffer created and filled in `UPLOAD` heap type:
- \code
- const UINT64 bufSize = 65536;
- const float* bufData = (...);
- D3D12_RESOURCE_DESC resourceDesc = {};
- resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
- resourceDesc.Alignment = 0;
- resourceDesc.Width = bufSize;
- resourceDesc.Height = 1;
- resourceDesc.DepthOrArraySize = 1;
- resourceDesc.MipLevels = 1;
- resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
- resourceDesc.SampleDesc.Count = 1;
- resourceDesc.SampleDesc.Quality = 0;
- resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
- resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
- D3D12MA::ALLOCATION_DESC allocationDesc = {};
- allocationDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
- D3D12Resource* resource;
- D3D12MA::Allocation* allocation;
- HRESULT hr = allocator->CreateResource(
- &allocationDesc,
- &resourceDesc,
- D3D12_RESOURCE_STATE_GENERIC_READ,
- NULL,
- &allocation,
- IID_PPV_ARGS(&resource));
- void* mappedPtr;
- hr = resource->Map(0, NULL, &mappedPtr);
- memcpy(mappedPtr, bufData, bufSize);
- resource->Unmap(0, NULL);
- \endcode
- \page custom_pools Custom memory pools
- A "pool" is a collection of memory blocks that share certain properties.
- Allocator creates 3 default pools: for `D3D12_HEAP_TYPE_DEFAULT`, `UPLOAD`, `READBACK`.
- A default pool automatically grows in size. Size of allocated blocks is also variable and managed automatically.
- Typical allocations are created in these pools. You can also create custom pools.
- \section custom_pools_usage Usage
- To create a custom pool, fill in structure D3D12MA::POOL_DESC and call function D3D12MA::Allocator::CreatePool
- to obtain object D3D12MA::Pool. Example:
- \code
- POOL_DESC poolDesc = {};
- poolDesc.HeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
- Pool* pool;
- HRESULT hr = allocator->CreatePool(&poolDesc, &pool);
- \endcode
- To allocate resources out of a custom pool, only set member D3D12MA::ALLOCATION_DESC::CustomPool.
- Example:
- \code
- ALLOCATION_DESC allocDesc = {};
- allocDesc.CustomPool = pool;
- D3D12_RESOURCE_DESC resDesc = ...
- Allocation* alloc;
- hr = allocator->CreateResource(&allocDesc, &resDesc,
- D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &alloc, IID_NULL, NULL);
- \endcode
- All allocations must be released before releasing the pool.
- The pool must be released before relasing the allocator.
- \code
- alloc->Release();
- pool->Release();
- \endcode
- \section custom_pools_features_and_benefits Features and benefits
- While it is recommended to use default pools whenever possible for simplicity and to give the allocator
- more opportunities for internal optimizations, custom pools may be useful in following cases:
- - To keep some resources separate from others in memory.
- - To keep track of memory usage of just a specific group of resources. %Statistics can be queried using
- D3D12MA::Pool::CalculateStatistics.
- - To use specific size of a memory block (`ID3D12Heap`). To set it, use member D3D12MA::POOL_DESC::BlockSize.
- When set to 0, the library uses automatically determined, variable block sizes.
- - To reserve some minimum amount of memory allocated. To use it, set member D3D12MA::POOL_DESC::MinBlockCount.
- - To limit maximum amount of memory allocated. To use it, set member D3D12MA::POOL_DESC::MaxBlockCount.
- - To use extended parameters of the D3D12 memory allocation. While resources created from default pools
- can only specify `D3D12_HEAP_TYPE_DEFAULT`, `UPLOAD`, `READBACK`, a custom pool may use non-standard
- `D3D12_HEAP_PROPERTIES` (member D3D12MA::POOL_DESC::HeapProperties) and `D3D12_HEAP_FLAGS`
- (D3D12MA::POOL_DESC::HeapFlags), which is useful e.g. for cross-adapter sharing or UMA
- (see also D3D12MA::Allocator::IsUMA).
- New versions of this library support creating **committed allocations in custom pools**.
- It is supported only when D3D12MA::POOL_DESC::BlockSize = 0.
- To use this feature, set D3D12MA::ALLOCATION_DESC::CustomPool to the pointer to your custom pool and
- D3D12MA::ALLOCATION_DESC::Flags to D3D12MA::ALLOCATION_FLAG_COMMITTED. Example:
- \code
- ALLOCATION_DESC allocDesc = {};
- allocDesc.CustomPool = pool;
- allocDesc.Flags = ALLOCATION_FLAG_COMMITTED;
- D3D12_RESOURCE_DESC resDesc = ...
- Allocation* alloc;
- ID3D12Resource* res;
- hr = allocator->CreateResource(&allocDesc, &resDesc,
- D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &alloc, IID_PPV_ARGS(&res));
- \endcode
- This feature may seem unnecessary, but creating committed allocations from custom pools may be useful
- in some cases, e.g. to have separate memory usage statistics for some group of resources or to use
- extended allocation parameters, like custom `D3D12_HEAP_PROPERTIES`, which are available only in custom pools.
- \page defragmentation Defragmentation
- Interleaved allocations and deallocations of many objects of varying size can
- cause fragmentation over time, which can lead to a situation where the library is unable
- to find a continuous range of free memory for a new allocation despite there is
- enough free space, just scattered across many small free ranges between existing
- allocations.
- To mitigate this problem, you can use defragmentation feature.
- It doesn't happen automatically though and needs your cooperation,
- because %D3D12MA is a low level library that only allocates memory.
- It cannot recreate buffers and textures in a new place as it doesn't remember the contents of `D3D12_RESOURCE_DESC` structure.
- It cannot copy their contents as it doesn't record any commands to a command list.
- Example:
- \code
- D3D12MA::DEFRAGMENTATION_DESC defragDesc = {};
- defragDesc.Flags = D3D12MA::DEFRAGMENTATION_FLAG_ALGORITHM_FAST;
- D3D12MA::DefragmentationContext* defragCtx;
- allocator->BeginDefragmentation(&defragDesc, &defragCtx);
- for(;;)
- {
- D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO pass;
- HRESULT hr = defragCtx->BeginPass(&pass);
- if(hr == S_OK)
- break;
- else if(hr != S_FALSE)
- // Handle error...
- for(UINT i = 0; i < pass.MoveCount; ++i)
- {
- // Inspect pass.pMoves[i].pSrcAllocation, identify what buffer/texture it represents.
- MyEngineResourceData* resData = (MyEngineResourceData*)pMoves[i].pSrcAllocation->GetPrivateData();
-
- // Recreate this buffer/texture as placed at pass.pMoves[i].pDstTmpAllocation.
- D3D12_RESOURCE_DESC resDesc = ...
- ID3D12Resource* newRes;
- hr = device->CreatePlacedResource(
- pass.pMoves[i].pDstTmpAllocation->GetHeap(),
- pass.pMoves[i].pDstTmpAllocation->GetOffset(), &resDesc,
- D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&newRes));
- // Check hr...
- // Store new resource in the pDstTmpAllocation.
- pass.pMoves[i].pDstTmpAllocation->SetResource(newRes);
- // Copy its content to the new place.
- cmdList->CopyResource(
- pass.pMoves[i].pDstTmpAllocation->GetResource(),
- pass.pMoves[i].pSrcAllocation->GetResource());
- }
-
- // Make sure the copy commands finished executing.
- cmdQueue->ExecuteCommandLists(...);
- // ...
- WaitForSingleObject(fenceEvent, INFINITE);
- // Update appropriate descriptors to point to the new places...
-
- hr = defragCtx->EndPass(&pass);
- if(hr == S_OK)
- break;
- else if(hr != S_FALSE)
- // Handle error...
- }
- defragCtx->Release();
- \endcode
- Although functions like D3D12MA::Allocator::CreateResource()
- create an allocation and a buffer/texture at once, these are just a shortcut for
- allocating memory and creating a placed resource.
- Defragmentation works on memory allocations only. You must handle the rest manually.
- Defragmentation is an iterative process that should repreat "passes" as long as related functions
- return `S_FALSE` not `S_OK`.
- In each pass:
- 1. D3D12MA::DefragmentationContext::BeginPass() function call:
- - Calculates and returns the list of allocations to be moved in this pass.
- Note this can be a time-consuming process.
- - Reserves destination memory for them by creating temporary destination allocations
- that you can query for their `ID3D12Heap` + offset using methods like D3D12MA::Allocation::GetHeap().
- 2. Inside the pass, **you should**:
- - Inspect the returned list of allocations to be moved.
- - Create new buffers/textures as placed at the returned destination temporary allocations.
- - Copy data from source to destination resources if necessary.
- - Store the pointer to the new resource in the temporary destination allocation.
- 3. D3D12MA::DefragmentationContext::EndPass() function call:
- - Frees the source memory reserved for the allocations that are moved.
- - Modifies source D3D12MA::Allocation objects that are moved to point to the destination reserved memory
- and destination resource, while source resource is released.
- - Frees `ID3D12Heap` blocks that became empty.
- Defragmentation algorithm tries to move all suitable allocations.
- You can, however, refuse to move some of them inside a defragmentation pass, by setting
- `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
- This is not recommended and may result in suboptimal packing of the allocations after defragmentation.
- If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.
- Inside a pass, for each allocation that should be moved:
- - You should copy its data from the source to the destination place by calling e.g. `CopyResource()`.
- - You need to make sure these commands finished executing before the source buffers/textures are released by D3D12MA::DefragmentationContext::EndPass().
- - If a resource doesn't contain any meaningful data, e.g. it is a transient render-target texture to be cleared,
- filled, and used temporarily in each rendering frame, you can just recreate this texture
- without copying its data.
- - If the resource is in `D3D12_HEAP_TYPE_READBACK` memory, you can copy its data on the CPU
- using `memcpy()`.
- - If you cannot move the allocation, you can set `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
- This will cancel the move.
- - D3D12MA::DefragmentationContext::EndPass() will then free the destination memory
- not the source memory of the allocation, leaving it unchanged.
- - If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time),
- you can set `pass.pMoves[i].Operation` to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY.
- - D3D12MA::DefragmentationContext::EndPass() will then free both source and destination memory, and will destroy the source D3D12MA::Allocation object.
- You can defragment a specific custom pool by calling D3D12MA::Pool::BeginDefragmentation
- or all the default pools by calling D3D12MA::Allocator::BeginDefragmentation (like in the example above).
- Defragmentation is always performed in each pool separately.
- Allocations are never moved between different heap types.
- The size of the destination memory reserved for a moved allocation is the same as the original one.
- Alignment of an allocation as it was determined using `GetResourceAllocationInfo()` is also respected after defragmentation.
- Buffers/textures should be recreated with the same `D3D12_RESOURCE_DESC` parameters as the original ones.
- You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved
- in each pass, e.g. to call it in sync with render frames and not to experience too big hitches.
- See members: D3D12MA::DEFRAGMENTATION_DESC::MaxBytesPerPass, D3D12MA::DEFRAGMENTATION_DESC::MaxAllocationsPerPass.
- <b>Thread safety:</b>
- It is safe to perform the defragmentation asynchronously to render frames and other Direct3D 12 and %D3D12MA
- usage, possibly from multiple threads, with the exception that allocations
- returned in D3D12MA::DEFRAGMENTATION_PASS_MOVE_INFO::pMoves shouldn't be released until the defragmentation pass is ended.
- During the call to D3D12MA::DefragmentationContext::BeginPass(), any operations on the memory pool
- affected by the defragmentation are blocked by a mutex.
- What it means in practice is that you shouldn't free any allocations from the defragmented pool
- since the moment a call to `BeginPass` begins. Otherwise, a thread performing the `allocation->Release()`
- would block for the time `BeginPass` executes and then free the allocation when it finishes, while the allocation
- could have ended up on the list of allocations to move.
- A solution to freeing allocations during defragmentation is to find such allocation on the list
- `pass.pMoves[i]` and set its operation to D3D12MA::DEFRAGMENTATION_MOVE_OPERATION_DESTROY instead of
- calling `allocation->Release()`, or simply deferring the release to the time after defragmentation finished.
- <b>Mapping</b> is out of scope of this library and so it is not preserved after an allocation is moved during defragmentation.
- You need to map the new resource yourself if needed.
- \note Defragmentation is not supported in custom pools created with D3D12MA::POOL_FLAG_ALGORITHM_LINEAR.
- \page statistics Statistics
- This library contains several functions that return information about its internal state,
- especially the amount of memory allocated from D3D12.
- \section statistics_numeric_statistics Numeric statistics
- If you need to obtain basic statistics about memory usage per memory segment group, together with current budget,
- you can call function D3D12MA::Allocator::GetBudget() and inspect structure D3D12MA::Budget.
- This is useful to keep track of memory usage and stay withing budget.
- Example:
- \code
- D3D12MA::Budget localBudget;
- allocator->GetBudget(&localBudget, NULL);
- printf("My GPU memory currently has %u allocations taking %llu B,\n",
- localBudget.Statistics.AllocationCount,
- localBudget.Statistics.AllocationBytes);
- printf("allocated out of %u D3D12 memory heaps taking %llu B,\n",
- localBudget.Statistics.BlockCount,
- localBudget.Statistics.BlockBytes);
- printf("D3D12 reports total usage %llu B with budget %llu B.\n",
- localBudget.UsageBytes,
- localBudget.BudgetBytes);
- \endcode
- You can query for more detailed statistics per heap type, memory segment group, and totals,
- including minimum and maximum allocation size and unused range size,
- by calling function D3D12MA::Allocator::CalculateStatistics() and inspecting structure D3D12MA::TotalStatistics.
- This function is slower though, as it has to traverse all the internal data structures,
- so it should be used only for debugging purposes.
- You can query for statistics of a custom pool using function D3D12MA::Pool::GetStatistics()
- or D3D12MA::Pool::CalculateStatistics().
- You can query for information about a specific allocation using functions of the D3D12MA::Allocation class,
- e.g. `GetSize()`, `GetOffset()`, `GetHeap()`.
- \section statistics_json_dump JSON dump
- You can dump internal state of the allocator to a string in JSON format using function D3D12MA::Allocator::BuildStatsString().
- The result is guaranteed to be correct JSON.
- It uses Windows Unicode (UTF-16) encoding.
- Any strings provided by user (see D3D12MA::Allocation::SetName())
- are copied as-is and properly escaped for JSON.
- It must be freed using function D3D12MA::Allocator::FreeStatsString().
- The format of this JSON string is not part of official documentation of the library,
- but it will not change in backward-incompatible way without increasing library major version number
- and appropriate mention in changelog.
- The JSON string contains all the data that can be obtained using D3D12MA::Allocator::CalculateStatistics().
- It can also contain detailed map of allocated memory blocks and their regions -
- free and occupied by allocations.
- This allows e.g. to visualize the memory or assess fragmentation.
- \page resource_aliasing Resource aliasing (overlap)
- New explicit graphics APIs (Vulkan and Direct3D 12), thanks to manual memory
- management, give an opportunity to alias (overlap) multiple resources in the
- same region of memory - a feature not available in the old APIs (Direct3D 11, OpenGL).
- It can be useful to save video memory, but it must be used with caution.
- For example, if you know the flow of your whole render frame in advance, you
- are going to use some intermediate textures or buffers only during a small range of render passes,
- and you know these ranges don't overlap in time, you can create these resources in
- the same place in memory, even if they have completely different parameters (width, height, format etc.).
- 
- Such scenario is possible using D3D12MA, but you need to create your resources
- using special function D3D12MA::Allocator::CreateAliasingResource.
- Before that, you need to allocate memory with parameters calculated using formula:
- - allocation size = max(size of each resource)
- - allocation alignment = max(alignment of each resource)
- Following example shows two different textures created in the same place in memory,
- allocated to fit largest of them.
- \code
- D3D12_RESOURCE_DESC resDesc1 = {};
- resDesc1.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
- resDesc1.Alignment = 0;
- resDesc1.Width = 1920;
- resDesc1.Height = 1080;
- resDesc1.DepthOrArraySize = 1;
- resDesc1.MipLevels = 1;
- resDesc1.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- resDesc1.SampleDesc.Count = 1;
- resDesc1.SampleDesc.Quality = 0;
- resDesc1.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
- resDesc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
- D3D12_RESOURCE_DESC resDesc2 = {};
- resDesc2.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
- resDesc2.Alignment = 0;
- resDesc2.Width = 1024;
- resDesc2.Height = 1024;
- resDesc2.DepthOrArraySize = 1;
- resDesc2.MipLevels = 0;
- resDesc2.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- resDesc2.SampleDesc.Count = 1;
- resDesc2.SampleDesc.Quality = 0;
- resDesc2.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
- resDesc2.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
- const D3D12_RESOURCE_ALLOCATION_INFO allocInfo1 =
- device->GetResourceAllocationInfo(0, 1, &resDesc1);
- const D3D12_RESOURCE_ALLOCATION_INFO allocInfo2 =
- device->GetResourceAllocationInfo(0, 1, &resDesc2);
- D3D12_RESOURCE_ALLOCATION_INFO finalAllocInfo = {};
- finalAllocInfo.Alignment = std::max(allocInfo1.Alignment, allocInfo2.Alignment);
- finalAllocInfo.SizeInBytes = std::max(allocInfo1.SizeInBytes, allocInfo2.SizeInBytes);
- D3D12MA::ALLOCATION_DESC allocDesc = {};
- allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
- allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
- D3D12MA::Allocation* alloc;
- hr = allocator->AllocateMemory(&allocDesc, &finalAllocInfo, &alloc);
- assert(alloc != NULL && alloc->GetHeap() != NULL);
- ID3D12Resource* res1;
- hr = allocator->CreateAliasingResource(
- alloc,
- 0, // AllocationLocalOffset
- &resDesc1,
- D3D12_RESOURCE_STATE_COMMON,
- NULL, // pOptimizedClearValue
- IID_PPV_ARGS(&res1));
- ID3D12Resource* res2;
- hr = allocator->CreateAliasingResource(
- alloc,
- 0, // AllocationLocalOffset
- &resDesc2,
- D3D12_RESOURCE_STATE_COMMON,
- NULL, // pOptimizedClearValue
- IID_PPV_ARGS(&res2));
- // You can use res1 and res2, but not at the same time!
- res2->Release();
- res1->Release();
- alloc->Release();
- \endcode
- Remember that using resouces that alias in memory requires proper synchronization.
- You need to issue a special barrier of type `D3D12_RESOURCE_BARRIER_TYPE_ALIASING`.
- You also need to treat a resource after aliasing as uninitialized - containing garbage data.
- For example, if you use `res1` and then want to use `res2`, you need to first initialize `res2`
- using either Clear, Discard, or Copy to the entire resource.
- Additional considerations:
- - D3D12 also allows to interpret contents of memory between aliasing resources consistently in some cases,
- which is called "data inheritance". For details, see
- Microsoft documentation chapter "Memory Aliasing and Data Inheritance".
- - You can create more complex layout where different textures and buffers are bound
- at different offsets inside one large allocation. For example, one can imagine
- a big texture used in some render passes, aliasing with a set of many small buffers
- used in some further passes. To bind a resource at non-zero offset of an allocation,
- call D3D12MA::Allocator::CreateAliasingResource with appropriate value of `AllocationLocalOffset` parameter.
- - Resources of the three categories: buffers, textures with `RENDER_TARGET` or `DEPTH_STENCIL` flags, and all other textures,
- can be placed in the same memory only when `allocator->GetD3D12Options().ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2`.
- Otherwise they must be placed in different memory heap types, and thus aliasing them is not possible.
- \page linear_algorithm Linear allocation algorithm
- Each D3D12 memory block managed by this library has accompanying metadata that
- keeps track of used and unused regions. By default, the metadata structure and
- algorithm tries to find best place for new allocations among free regions to
- optimize memory usage. This way you can allocate and free objects in any order.
- 
- Sometimes there is a need to use simpler, linear allocation algorithm. You can
- create custom pool that uses such algorithm by adding flag
- D3D12MA::POOL_FLAG_ALGORITHM_LINEAR to D3D12MA::POOL_DESC::Flags while creating
- D3D12MA::Pool object. Then an alternative metadata management is used. It always
- creates new allocations after last one and doesn't reuse free regions after
- allocations freed in the middle. It results in better allocation performance and
- less memory consumed by metadata.
- 
- With this one flag, you can create a custom pool that can be used in many ways:
- free-at-once, stack, double stack, and ring buffer. See below for details.
- You don't need to specify explicitly which of these options you are going to use - it is detected automatically.
- \section linear_algorithm_free_at_once Free-at-once
- In a pool that uses linear algorithm, you still need to free all the allocations
- individually by calling `allocation->Release()`. You can free
- them in any order. New allocations are always made after last one - free space
- in the middle is not reused. However, when you release all the allocation and
- the pool becomes empty, allocation starts from the beginning again. This way you
- can use linear algorithm to speed up creation of allocations that you are going
- to release all at once.
- 
- This mode is also available for pools created with D3D12MA::POOL_DESC::MaxBlockCount
- value that allows multiple memory blocks.
- \section linear_algorithm_stack Stack
- When you free an allocation that was created last, its space can be reused.
- Thanks to this, if you always release allocations in the order opposite to their
- creation (LIFO - Last In First Out), you can achieve behavior of a stack.
- 
- This mode is also available for pools created with D3D12MA::POOL_DESC::MaxBlockCount
- value that allows multiple memory blocks.
- \section linear_algorithm_double_stack Double stack
- The space reserved by a custom pool with linear algorithm may be used by two
- stacks:
- - First, default one, growing up from offset 0.
- - Second, "upper" one, growing down from the end towards lower offsets.
- To make allocation from the upper stack, add flag D3D12MA::ALLOCATION_FLAG_UPPER_ADDRESS
- to D3D12MA::ALLOCATION_DESC::Flags.
- 
- Double stack is available only in pools with one memory block -
- D3D12MA::POOL_DESC::MaxBlockCount must be 1. Otherwise behavior is undefined.
- When the two stacks' ends meet so there is not enough space between them for a
- new allocation, such allocation fails with usual `E_OUTOFMEMORY` error.
- \section linear_algorithm_ring_buffer Ring buffer
- When you free some allocations from the beginning and there is not enough free space
- for a new one at the end of a pool, allocator's "cursor" wraps around to the
- beginning and starts allocation there. Thanks to this, if you always release
- allocations in the same order as you created them (FIFO - First In First Out),
- you can achieve behavior of a ring buffer / queue.
- 
- Ring buffer is available only in pools with one memory block -
- D3D12MA::POOL_DESC::MaxBlockCount must be 1. Otherwise behavior is undefined.
- \section linear_algorithm_additional_considerations Additional considerations
- Linear algorithm can also be used with \ref virtual_allocator.
- See flag D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR.
- \page virtual_allocator Virtual allocator
- As an extra feature, the core allocation algorithm of the library is exposed through a simple and convenient API of "virtual allocator".
- It doesn't allocate any real GPU memory. It just keeps track of used and free regions of a "virtual block".
- You can use it to allocate your own memory or other objects, even completely unrelated to D3D12.
- A common use case is sub-allocation of pieces of one large GPU buffer.
- \section virtual_allocator_creating_virtual_block Creating virtual block
- To use this functionality, there is no main "allocator" object.
- You don't need to have D3D12MA::Allocator object created.
- 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:
- -# Fill in D3D12MA::ALLOCATOR_DESC structure.
- -# Call D3D12MA::CreateVirtualBlock. Get new D3D12MA::VirtualBlock object.
- Example:
- \code
- D3D12MA::VIRTUAL_BLOCK_DESC blockDesc = {};
- blockDesc.Size = 1048576; // 1 MB
- D3D12MA::VirtualBlock *block;
- HRESULT hr = CreateVirtualBlock(&blockDesc, &block);
- \endcode
- \section virtual_allocator_making_virtual_allocations Making virtual allocations
- D3D12MA::VirtualBlock object contains internal data structure that keeps track of free and occupied regions
- using the same code as the main D3D12 memory allocator.
- A single allocation is identified by a lightweight structure D3D12MA::VirtualAllocation.
- You will also likely want to know the offset at which the allocation was made in the block.
- In order to make an allocation:
- -# Fill in D3D12MA::VIRTUAL_ALLOCATION_DESC structure.
- -# Call D3D12MA::VirtualBlock::Allocate. Get new D3D12MA::VirtualAllocation value that identifies the allocation.
- Example:
- \code
- D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};
- allocDesc.Size = 4096; // 4 KB
- D3D12MA::VirtualAllocation alloc;
- UINT64 allocOffset;
- hr = block->Allocate(&allocDesc, &alloc, &allocOffset);
- if(SUCCEEDED(hr))
- {
- // Use the 4 KB of your memory starting at allocOffset.
- }
- else
- {
- // Allocation failed - no space for it could be found. Handle this error!
- }
- \endcode
- \section virtual_allocator_deallocation Deallocation
- When no longer needed, an allocation can be freed by calling D3D12MA::VirtualBlock::FreeAllocation.
- When whole block is no longer needed, the block object can be released by calling `block->Release()`.
- All allocations must be freed before the block is destroyed, which is checked internally by an assert.
- 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 -
- a feature not available in normal D3D12 memory allocator.
- Example:
- \code
- block->FreeAllocation(alloc);
- block->Release();
- \endcode
- \section virtual_allocator_allocation_parameters Allocation parameters
- You can attach a custom pointer to each allocation by using D3D12MA::VirtualBlock::SetAllocationPrivateData.
- Its default value is `NULL`.
- 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
- larger data structure containing more information. Example:
- \code
- struct CustomAllocData
- {
- std::string m_AllocName;
- };
- CustomAllocData* allocData = new CustomAllocData();
- allocData->m_AllocName = "My allocation 1";
- block->SetAllocationPrivateData(alloc, allocData);
- \endcode
- The pointer can later be fetched, along with allocation offset and size, by passing the allocation handle to function
- D3D12MA::VirtualBlock::GetAllocationInfo and inspecting returned structure D3D12MA::VIRTUAL_ALLOCATION_INFO.
- If you allocated a new object to be used as the custom pointer, don't forget to delete that object before freeing the allocation!
- Example:
- \code
- VIRTUAL_ALLOCATION_INFO allocInfo;
- block->GetAllocationInfo(alloc, &allocInfo);
- delete (CustomAllocData*)allocInfo.pPrivateData;
- block->FreeAllocation(alloc);
- \endcode
- \section virtual_allocator_alignment_and_units Alignment and units
- It feels natural to express sizes and offsets in bytes.
- 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
- D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment to request it. Example:
- \code
- D3D12MA::VIRTUAL_ALLOCATION_DESC allocDesc = {};
- allocDesc.Size = 4096; // 4 KB
- allocDesc.Alignment = 4; // Returned offset must be a multiply of 4 B
- D3D12MA::VirtualAllocation alloc;
- UINT64 allocOffset;
- hr = block->Allocate(&allocDesc, &alloc, &allocOffset);
- \endcode
- Alignments of different allocations made from one block may vary.
- However, if all alignments and sizes are always multiply of some size e.g. 4 B or `sizeof(MyDataStruct)`,
- you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes.
- It might be more convenient, but you need to make sure to use this new unit consistently in all the places:
- - D3D12MA::VIRTUAL_BLOCK_DESC::Size
- - D3D12MA::VIRTUAL_ALLOCATION_DESC::Size and D3D12MA::VIRTUAL_ALLOCATION_DESC::Alignment
- - Using offset returned by D3D12MA::VirtualBlock::Allocate and D3D12MA::VIRTUAL_ALLOCATION_INFO::Offset
- \section virtual_allocator_statistics Statistics
- You can obtain brief statistics of a virtual block using D3D12MA::VirtualBlock::GetStatistics().
- The function fills structure D3D12MA::Statistics - same as used by the normal D3D12 memory allocator.
- Example:
- \code
- D3D12MA::Statistics stats;
- block->GetStatistics(&stats);
- printf("My virtual block has %llu bytes used by %u virtual allocations\n",
- stats.AllocationBytes, stats.AllocationCount);
- \endcode
- More detailed statistics can be obtained using function D3D12MA::VirtualBlock::CalculateStatistics(),
- but they are slower to calculate.
- You can also request a full list of allocations and free regions as a string in JSON format by calling
- D3D12MA::VirtualBlock::BuildStatsString.
- Returned string must be later freed using D3D12MA::VirtualBlock::FreeStatsString.
- The format of this string may differ from the one returned by the main D3D12 allocator, but it is similar.
- \section virtual_allocator_additional_considerations Additional considerations
- Alternative, linear algorithm can be used with virtual allocator - see flag
- D3D12MA::VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR and documentation: \ref linear_algorithm.
- Note that the "virtual allocator" functionality is implemented on a level of individual memory blocks.
- Keeping track of a whole collection of blocks, allocating new ones when out of free space,
- deleting empty ones, and deciding which one to try first for a new allocation must be implemented by the user.
- \page configuration Configuration
- Please check file `D3D12MemAlloc.cpp` lines between "Configuration Begin" and
- "Configuration End" to find macros that you can define to change the behavior of
- the library, primarily for debugging purposes.
- \section custom_memory_allocator Custom CPU memory allocator
- If you use custom allocator for CPU memory rather than default C++ operator `new`
- and `delete` or `malloc` and `free` functions, you can make this library using
- your allocator as well by filling structure D3D12MA::ALLOCATION_CALLBACKS and
- passing it as optional member D3D12MA::ALLOCATOR_DESC::pAllocationCallbacks.
- Functions pointed there will be used by the library to make any CPU-side
- allocations. Example:
- \code
- #include <malloc.h>
- void* CustomAllocate(size_t Size, size_t Alignment, void* pPrivateData)
- {
- void* memory = _aligned_malloc(Size, Alignment);
- // Your extra bookkeeping here...
- return memory;
- }
- void CustomFree(void* pMemory, void* pPrivateData)
- {
- // Your extra bookkeeping here...
- _aligned_free(pMemory);
- }
- (...)
- D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};
- allocationCallbacks.pAllocate = &CustomAllocate;
- allocationCallbacks.pFree = &CustomFree;
- D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
- allocatorDesc.pDevice = device;
- allocatorDesc.pAdapter = adapter;
- allocatorDesc.pAllocationCallbacks = &allocationCallbacks;
- D3D12MA::Allocator* allocator;
- HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
- \endcode
- \section debug_margins Debug margins
- By default, allocations are laid out in memory blocks next to each other if possible
- (considering required alignment returned by `ID3D12Device::GetResourceAllocationInfo`).
- 
- Define macro `D3D12MA_DEBUG_MARGIN` to some non-zero value (e.g. 16) inside "D3D12MemAlloc.cpp"
- to enforce specified number of bytes as a margin after every allocation.
- 
- If your bug goes away after enabling margins, it means it may be caused by memory
- being overwritten outside of allocation boundaries. It is not 100% certain though.
- Change in application behavior may also be caused by different order and distribution
- of allocations across memory blocks after margins are applied.
- Margins work with all memory heap types.
- Margin is applied only to placed allocations made out of memory heaps and not to committed
- allocations, which have their own, implicit memory heap of specific size.
- It is thus not applied to allocations made using D3D12MA::ALLOCATION_FLAG_COMMITTED flag
- or those automatically decided to put into committed allocations, e.g. due to its large size.
- Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space.
- Note that enabling margins increases memory usage and fragmentation.
- Margins do not apply to \ref virtual_allocator.
- \page general_considerations General considerations
- \section general_considerations_thread_safety Thread safety
- - The library has no global state, so separate D3D12MA::Allocator objects can be used independently.
- In typical applications there should be no need to create multiple such objects though - one per `ID3D12Device` is enough.
- - All calls to methods of D3D12MA::Allocator class are safe to be made from multiple
- threads simultaneously because they are synchronized internally when needed.
- - When the allocator is created with D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED,
- calls to methods of D3D12MA::Allocator class must be made from a single thread or synchronized by the user.
- Using this flag may improve performance.
- - D3D12MA::VirtualBlock is not safe to be used from multiple threads simultaneously.
- \section general_considerations_versioning_and_compatibility Versioning and compatibility
- The library uses [**Semantic Versioning**](https://semver.org/),
- which means version numbers follow convention: Major.Minor.Patch (e.g. 2.3.0), where:
- - Incremented Patch version means a release is backward- and forward-compatible,
- introducing only some internal improvements, bug fixes, optimizations etc.
- or changes that are out of scope of the official API described in this documentation.
- - Incremented Minor version means a release is backward-compatible,
- so existing code that uses the library should continue to work, while some new
- symbols could have been added: new structures, functions, new values in existing
- enums and bit flags, new structure members, but not new function parameters.
- - Incrementing Major version means a release could break some backward compatibility.
- All changes between official releases are documented in file "CHANGELOG.md".
- \warning Backward compatiblity is considered on the level of C++ source code, not binary linkage.
- Adding new members to existing structures is treated as backward compatible if initializing
- the new members to binary zero results in the old behavior.
- You should always fully initialize all library structures to zeros and not rely on their
- exact binary size.
- \section general_considerations_features_not_supported Features not supported
- Features deliberately excluded from the scope of this library:
- - **Descriptor allocation.** Although also called "heaps", objects that represent
- descriptors are separate part of the D3D12 API from buffers and textures.
- You can still use \ref virtual_allocator to manage descriptors and their ranges inside a descriptor heap.
- - **Support for reserved (tiled) resources.** We don't recommend using them.
- - Support for `ID3D12Device::Evict` and `MakeResident`. We don't recommend using them.
- You can call them on the D3D12 objects manually.
- Plese keep in mind, however, that eviction happens on the level of entire `ID3D12Heap` memory blocks
- and not individual buffers or textures which may be placed inside them.
- - **Handling CPU memory allocation failures.** When dynamically creating small C++
- objects in CPU memory (not the GPU memory), allocation failures are not
- handled gracefully, because that would complicate code significantly and
- is usually not needed in desktop PC applications anyway.
- Success of an allocation is just checked with an assert.
- - **Code free of any compiler warnings.**
- There are many preprocessor macros that make some variables unused, function parameters unreferenced,
- or conditional expressions constant in some configurations.
- The code of this library should not be bigger or more complicated just to silence these warnings.
- It is recommended to disable such warnings instead.
- - This is a C++ library. **Bindings or ports to any other programming languages** are welcome as external projects but
- are not going to be included into this repository.
- */
|