2019-05-20 11:46:23 +00:00
//
2020-02-07 14:38:52 +00:00
// Copyright (c) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
2019-05-20 11:46:23 +00:00
//
// 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
2020-03-24 16:27:45 +00:00
< b > Version 2.0 .0 - development < / b > ( 2020 - 03 - 24 )
2019-05-20 11:46:23 +00:00
2020-02-07 14:38:52 +00:00
Copyright ( c ) 2019 - 2020 Advanced Micro Devices , Inc . All rights reserved . \ n
2019-05-20 11:46:23 +00:00
License : MIT
Documentation of all members : D3D12MemAlloc . h
\ section main_table_of_contents Table of contents
- < b > User guide < / b >
- \ subpage quick_start
- [ Project setup ] ( @ ref quick_start_project_setup )
- [ Creating resources ] ( @ ref quick_start_creating_resources )
- [ Mapping memory ] ( @ ref quick_start_mapping_memory )
- \ subpage configuration
- [ Custom CPU memory allocator ] ( @ ref custom_memory_allocator )
- \ subpage general_considerations
- [ Thread safety ] ( @ ref general_considerations_thread_safety )
- [ Future plans ] ( @ ref general_considerations_future_plans )
- [ Features not supported ] ( @ ref general_considerations_features_not_supported )
\ section main_see_also See also
2019-07-23 11:21:08 +00:00
- [ Product page on GPUOpen ] ( https : //gpuopen.com/gaming-product/d3d12-memory-allocator/)
2019-05-20 11:46:23 +00:00
- [ Source repository on GitHub ] ( https : //github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator)
\ 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
2020-01-27 16:34:49 +00:00
IDXGIAdapter * adapter = ( . . . )
2019-05-20 11:46:23 +00:00
ID3D12Device * device = ( . . . )
D3D12MA : : ALLOCATOR_DESC allocatorDesc = { } ;
allocatorDesc . pDevice = device ;
2020-01-27 16:34:49 +00:00
allocatorDesc . pAdapter = adapter ;
2019-05-20 11:46:23 +00:00
D3D12MA : : Allocator * allocator ;
HRESULT hr = D3D12MA : : CreateAllocator ( & allocatorDesc , & allocator ) ;
\ endcode
( 5. ) Right before destroying the D3D12 device , destroy the allocator object .
Please note that objects of this library must be destroyed by calling ` Release `
method ( despite they are not COM interfaces and no reference counting is involved ) .
\ 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 also returns a new object of type D3D12MA : : Allocation , created along
with usual ` ID3D12Resource ` . It represents allocated memory and can be queried
2019-11-05 15:29:45 +00:00
for size , offset , ` ID3D12Resource ` , and ` ID3D12Heap ` if needed .
2019-05-20 11:46:23 +00:00
\ 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 = { } ;
allocDesc . HeapType = D3D12_HEAP_TYPE_DEFAULT ;
D3D12Resource * resource ;
D3D12MA : : Allocation * allocation ;
HRESULT hr = allocator - > CreateResource (
& allocationDesc ,
& resourceDesc ,
D3D12_RESOURCE_STATE_COPY_DEST ,
NULL ,
& allocation ,
IID_PPV_ARGS ( & resource ) ) ;
\ endcode
You need to remember both resource and allocation objects and destroy them
separately when no longer needed .
\ code
allocation - > Release ( ) ;
resource - > 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 .
2019-11-05 15:29:45 +00:00
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 ` ) .
2019-05-20 11:46:23 +00:00
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_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 ] ( https : //docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12resource-map).
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 linked documentation 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 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 * pUserData )
{
void * memory = _aligned_malloc ( Size , Alignment ) ;
// Your extra bookkeeping here...
return memory ;
}
void CustomFree ( void * pMemory , void * pUserData )
{
// Your extra bookkeeping here...
_aligned_free ( pMemory ) ;
}
( . . . )
D3D12MA : : ALLOCATION_CALLBACKS allocationCallbacks = { } ;
allocationCallbacks . pAllocate = & CustomAllocate ;
allocationCallbacks . pFree = & CustomFree ;
D3D12MA : : ALLOCATOR_DESC allocatorDesc = { } ;
allocatorDesc . pDevice = device ;
2020-01-27 16:34:49 +00:00
allocatorDesc . pAdapter = adapter ;
2019-05-20 11:46:23 +00:00
allocatorDesc . pAllocationCallbacks = & allocationCallbacks ;
D3D12MA : : Allocator * allocator ;
HRESULT hr = D3D12MA : : CreateAllocator ( & allocatorDesc , & allocator ) ;
\ endcode
\ 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 .
\ section general_considerations_future_plans Future plans
Features planned for future releases :
Near future : feature parity with [ Vulkan Memory Allocator ] ( https : //github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/), including:
- Custom memory pools
- Alternative allocation algorithms : linear allocator , buddy allocator
2019-09-30 12:30:04 +00:00
- JSON dump that can be visualized on a picture
2019-05-20 11:46:23 +00:00
- Support for priorities using ` ID3D12Device1 : : SetResidencyPriority `
Later :
- Memory defragmentation
- Support for multi - GPU ( multi - adapter )
\ 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 .
- Support for ` D3D12_HEAP_TYPE_CUSTOM ` . Only the default heap types are supported :
2020-01-27 16:34:49 +00:00
` UPLOAD ` , ` DEFAULT ` , ` READBACK ` .
2019-05-20 11:46:23 +00:00
- Support for reserved ( tiled ) resources . We don ' t recommend using them .
- Support for ` ID3D12Device : : Evict ` and ` MakeResident ` . We don ' t recommend using them .
*/
2019-11-20 13:07:21 +00:00
// 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
# define D3D12MA_DXGI_1_4 1
# endif
2019-10-11 09:11:28 +00:00
// If using this library on a platform different than Windows PC, you should
2019-11-20 13:07:21 +00:00
// include D3D12-compatible header before this library on your own and define this macro.
# ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
2019-10-11 09:11:28 +00:00
# include <d3d12.h>
2019-11-20 13:07:21 +00:00
# include <dxgi.h>
2019-10-11 09:11:28 +00:00
# endif
2019-05-20 11:46:23 +00:00
2020-03-11 15:48:40 +00:00
/*
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 4 K and their size a multiply of 4 K instead of 64 K .
# 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
2019-05-20 11:46:23 +00:00
/// \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
/// \endcond
namespace D3D12MA
{
/// \cond INTERNAL
class AllocatorPimpl ;
2019-10-11 09:11:28 +00:00
class NormalBlock ;
2019-05-20 11:46:23 +00:00
class BlockVector ;
2019-10-11 14:20:45 +00:00
class JsonWriter ;
2019-05-20 11:46:23 +00:00
/// \endcond
/// Pointer to custom callback function that allocates CPU memory.
typedef void * ( * ALLOCATE_FUNC_PTR ) ( size_t Size , size_t Alignment , void * pUserData ) ;
/**
\ brief Pointer to custom callback function that deallocates CPU memory .
` pMemory = null ` should be accepted and ignored .
*/
typedef void ( * FREE_FUNC_PTR ) ( void * pMemory , void * pUserData ) ;
/// 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 * pUserData ;
} ;
/// \brief Bit flags to be used with ALLOCATION_DESC::Flags.
typedef 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 .
*/
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 # ALLOCATION_FLAG_COMMITTED and
# ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.
*/
ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2 ,
2019-11-20 13:07:21 +00:00
2020-01-27 16:34:49 +00:00
/** Create allocation only if additional memory required for it, if any, won't exceed
memory budget . Otherwise return ` E_OUTOFMEMORY ` .
2019-11-20 13:07:21 +00:00
*/
ALLOCATION_FLAG_WITHIN_BUDGET = 0x4 ,
2019-05-20 11:46:23 +00:00
} ALLOCATION_FLAGS ;
/// \brief Parameters of created 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 ` .
*/
D3D12_HEAP_TYPE HeapType ;
2020-03-19 10:59:16 +00:00
/** \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 .
In case of D3D12MA : : Allocator : : GetD3D12Options ( ) ` . ResourceHeapTier = = D3D12_RESOURCE_HEAP_TIER_1 ` ,
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 ( ) and
D3D12MA : : Allocator : : GetD3D12Options ( ) ` . ResourceHeapTier = = D3D12_RESOURCE_HEAP_TIER_1 ` ,
you must specify one of those ` ALLOW_ONLY ` flags . When it ' s ` TIER_2 ` , you can leave it 0.
- If configuration macro ` D3D12MA_ALLOW_SHADER_ATOMICS ` is set to 1 ( which is the default ) ,
` D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS ` is added automatically wherever it might be needed .
- 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 .
*/
D3D12_HEAP_FLAGS ExtraHeapFlags ;
2019-05-20 11:46:23 +00:00
} ;
/** \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 .
2019-10-11 09:11:28 +00:00
The object also remembers ` ID3D12Resource ` and " owns " a reference to it ,
so it calls ` Release ( ) ` on the resource when destroyed .
2019-05-20 11:46:23 +00:00
*/
class Allocation
{
public :
/** \brief Deletes this object.
This function must be used instead of destructor , which is private .
There is no reference counting involved .
*/
void Release ( ) ;
/** \brief Returns offset in bytes from the start of memory heap.
If the Allocation represents committed resource with implicit heap , returns 0.
*/
UINT64 GetOffset ( ) const ;
/** \brief Returns size in bytes of the resource.
Works also with committed resources .
*/
UINT64 GetSize ( ) const { return m_Size ; }
2019-10-11 09:11:28 +00:00
/** \brief Returns D3D12 resource associated with this object.
Calling this method doesn ' t increment resource ' s reference counter .
*/
ID3D12Resource * GetResource ( ) const { return m_Resource ; }
2019-05-20 11:46:23 +00:00
/** \brief Returns memory heap that the resource is created in.
If the Allocation represents committed resource with implicit heap , returns NULL .
*/
ID3D12Heap * GetHeap ( ) const ;
/** \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 ; }
2020-03-16 18:36:15 +00:00
/** \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 ] ( https : //docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource#notes-on-the-required-resource-initialization).
Please note that rendering a fullscreen triangle or quad to the texture as
a render target is not a proper way of initialization !
2020-03-24 16:27:45 +00:00
See also articles :
[ " Coming to DirectX 12: More control over memory allocation " ] ( https : //devblogs.microsoft.com/directx/coming-to-directx-12-more-control-over-memory-allocation/),
[ " Initializing DX12 Textures After Allocation and Aliasing " ] ( https : //asawicki.info/news_1724_initializing_dx12_textures_after_allocation_and_aliasing).
2020-03-16 18:36:15 +00:00
*/
BOOL WasZeroInitialized ( ) const { return m_PackedData . WasZeroInitialized ( ) ; }
2019-05-20 11:46:23 +00:00
private :
friend class AllocatorPimpl ;
friend class BlockVector ;
2019-10-11 14:20:45 +00:00
friend class JsonWriter ;
2019-05-20 11:46:23 +00:00
template < typename T > friend void D3D12MA_DELETE ( const ALLOCATION_CALLBACKS & , T * ) ;
2020-01-22 15:33:39 +00:00
template < typename T > friend class PoolAllocator ;
2019-05-20 11:46:23 +00:00
enum Type
{
TYPE_COMMITTED ,
TYPE_PLACED ,
2019-10-11 09:11:28 +00:00
TYPE_HEAP ,
2019-05-20 11:46:23 +00:00
TYPE_COUNT
2020-03-16 15:36:37 +00:00
} ;
AllocatorPimpl * m_Allocator ;
2019-05-20 11:46:23 +00:00
UINT64 m_Size ;
2019-10-11 09:11:28 +00:00
ID3D12Resource * m_Resource ;
2019-10-11 14:20:45 +00:00
UINT m_CreationFrameIndex ;
2019-05-20 11:46:23 +00:00
wchar_t * m_Name ;
union
{
struct
{
D3D12_HEAP_TYPE heapType ;
} m_Committed ;
struct
{
UINT64 offset ;
2019-10-11 09:11:28 +00:00
NormalBlock * block ;
2019-05-20 11:46:23 +00:00
} m_Placed ;
2019-10-11 09:11:28 +00:00
struct
{
D3D12_HEAP_TYPE heapType ;
ID3D12Heap * heap ;
} m_Heap ;
2019-05-20 11:46:23 +00:00
} ;
2020-03-16 15:36:37 +00:00
struct PackedData
{
public :
PackedData ( ) :
2020-03-16 18:36:15 +00:00
m_Type ( 0 ) , m_ResourceDimension ( 0 ) , m_ResourceFlags ( 0 ) , m_TextureLayout ( 0 ) , m_WasZeroInitialized ( 0 ) { }
2020-03-16 15:36:37 +00:00
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 ; }
2020-03-16 18:36:15 +00:00
BOOL WasZeroInitialized ( ) const { return ( BOOL ) m_WasZeroInitialized ; }
2020-03-16 15:36:37 +00:00
2020-03-16 15:40:29 +00:00
void SetType ( Type type ) ;
void SetResourceDimension ( D3D12_RESOURCE_DIMENSION resourceDimension ) ;
void SetResourceFlags ( D3D12_RESOURCE_FLAGS resourceFlags ) ;
void SetTextureLayout ( D3D12_TEXTURE_LAYOUT textureLayout ) ;
2020-03-16 18:36:15 +00:00
void SetWasZeroInitialized ( BOOL wasZeroInitialized ) { m_WasZeroInitialized = wasZeroInitialized ? 1 : 0 ; }
2020-03-16 15:36:37 +00:00
private :
UINT m_Type : 2 ; // enum Type
UINT m_ResourceDimension : 3 ; // enum D3D12_RESOURCE_DIMENSION
UINT m_ResourceFlags : 7 ; // flags D3D12_RESOURCE_FLAGS
UINT m_TextureLayout : 2 ; // enum D3D12_TEXTURE_LAYOUT
2020-03-16 18:36:15 +00:00
UINT m_WasZeroInitialized : 1 ; // BOOL
2020-03-16 15:36:37 +00:00
} m_PackedData ;
2020-03-16 18:36:15 +00:00
Allocation ( AllocatorPimpl * allocator , UINT64 size , BOOL wasZeroInitialized ) ;
2019-05-20 11:46:23 +00:00
~ Allocation ( ) ;
2020-01-31 13:48:41 +00:00
void InitCommitted ( D3D12_HEAP_TYPE heapType ) ;
void InitPlaced ( UINT64 offset , UINT64 alignment , NormalBlock * block ) ;
void InitHeap ( D3D12_HEAP_TYPE heapType , ID3D12Heap * heap ) ;
2019-10-11 14:20:45 +00:00
void SetResource ( ID3D12Resource * resource , const D3D12_RESOURCE_DESC * pResourceDesc ) ;
2019-05-20 11:46:23 +00:00
void FreeName ( ) ;
D3D12MA_CLASS_NO_COPY ( Allocation )
} ;
/// \brief Bit flags to be used with ALLOCATOR_DESC::Flags.
typedef 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 ,
2019-10-23 13:21:21 +00:00
/**
Every allocation will have its own memory block .
To be used for debugging purposes .
*/
ALLOCATOR_FLAG_ALWAYS_COMMITTED = 0x2 ,
2019-05-20 11:46:23 +00:00
} ALLOCATOR_FLAGS ;
/// \brief Parameters of created Allocator object. To be used with CreateAllocator().
struct ALLOCATOR_DESC
{
/// Flags.
ALLOCATOR_FLAGS Flags ;
2019-11-20 13:07:21 +00:00
/** Direct3D device object that the allocator should be attached to.
2020-01-27 16:34:49 +00:00
Allocator is doing ` AddRef ` / ` Release ` on this object .
2019-11-20 13:07:21 +00:00
*/
2019-05-20 11:46:23 +00:00
ID3D12Device * pDevice ;
/** \brief Preferred size of a single `ID3D12Heap` block to be allocated.
Set to 0 to use default , which is currently 256 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 ;
2019-11-20 13:07:21 +00:00
2020-01-27 16:34:49 +00:00
/** DXGI Adapter object that you use for D3D12 and this allocator.
2019-11-20 13:07:21 +00:00
2020-01-27 16:34:49 +00:00
Allocator is doing ` AddRef ` / ` Release ` on this object .
2019-11-20 13:07:21 +00:00
*/
IDXGIAdapter * pAdapter ;
2019-05-20 11:46:23 +00:00
} ;
2019-09-30 12:30:04 +00:00
/**
\ brief Number of D3D12 memory heap types supported .
*/
const UINT HEAP_TYPE_COUNT = 3 ;
/**
\ brief Calculated statistics of memory usage in entire allocator .
*/
struct StatInfo
{
/// Number of memory blocks (heaps) allocated.
UINT BlockCount ;
/// Number of D3D12MA::Allocation objects allocated.
UINT AllocationCount ;
/// Number of free ranges of memory between allocations.
UINT UnusedRangeCount ;
/// Total number of bytes occupied by all allocations.
UINT64 UsedBytes ;
/// Total number of bytes occupied by unused ranges.
UINT64 UnusedBytes ;
UINT64 AllocationSizeMin ;
UINT64 AllocationSizeAvg ;
UINT64 AllocationSizeMax ;
UINT64 UnusedRangeSizeMin ;
UINT64 UnusedRangeSizeAvg ;
UINT64 UnusedRangeSizeMax ;
} ;
/**
\ brief General statistics from the current state of the allocator .
*/
struct Stats
{
/// Total statistics from all heap types.
StatInfo Total ;
/**
One StatInfo for each type of heap located at the following indices :
0 - DEFAULT , 1 - UPLOAD , 2 - READBACK .
*/
StatInfo HeapType [ HEAP_TYPE_COUNT ] ;
} ;
2019-11-20 13:07:21 +00:00
/** \brief Statistics of current memory usage and available budget, in bytes, for GPU or CPU memory.
*/
struct Budget
{
/** \brief Sum size of all memory blocks allocated from particular heap type, in bytes.
*/
UINT64 BlockBytes ;
/** \brief Sum size of all allocations created in particular heap type, in bytes.
Always less or equal than ` BlockBytes ` .
Difference ` BlockBytes - AllocationBytes ` is the amount of memory allocated but unused -
available for new allocations or wasted due to fragmentation .
*/
UINT64 AllocationBytes ;
/** \brief Estimated current memory usage of the program, in bytes.
2020-01-27 16:34:49 +00:00
Fetched from system using ` IDXGIAdapter3 : : QueryVideoMemoryInfo ` if enabled .
2019-11-20 13:07:21 +00:00
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
memory blocks allocated outside of this library , if any .
*/
2020-03-18 15:54:20 +00:00
UINT64 UsageBytes ;
2019-11-20 13:07:21 +00:00
/** \brief Estimated amount of memory available to the program, in bytes.
2020-01-27 16:34:49 +00:00
Fetched from system using ` IDXGIAdapter3 : : QueryVideoMemoryInfo ` if enabled .
2019-11-20 13:07:21 +00:00
2020-01-27 16:34:49 +00:00
It might be different ( most probably smaller ) than memory sizes reported in ` DXGI_ADAPTER_DESC ` due to factors
2019-11-20 13:07:21 +00:00
external to the program , like other programs also consuming system resources .
2020-03-18 15:54:20 +00:00
Difference ` BudgetBytes - UsageBytes ` is the amount of additional memory that can probably
2019-11-20 13:07:21 +00:00
be allocated without problems . Exceeding the budget may result in various problems .
*/
2020-03-18 15:54:20 +00:00
UINT64 BudgetBytes ;
2019-11-20 13:07:21 +00:00
} ;
2019-05-20 11:46:23 +00:00
/**
\ 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 Allocator : : 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 Allocator
{
public :
/** \brief Deletes this object.
This function must be used instead of destructor , which is private .
There is no reference counting involved .
*/
void Release ( ) ;
/// Returns cached options retrieved from D3D12 device.
const D3D12_FEATURE_DATA_D3D12_OPTIONS & GetD3D12Options ( ) 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 .
2019-10-11 09:11:28 +00:00
If ` ppvResource ` is null , you receive only ` ppAllocation ` object from this function .
It holds pointer to ` ID3D12Resource ` that can be queried using function D3D12 : : 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 2 , 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 created . Must be ` __uuidof ( ID3D12Resource ) ` .
\ param [ out ] ppvResource Optional . If not null , filled with pointer to new resouce created .
2019-05-20 11:46:23 +00:00
*/
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 ) ;
2020-01-23 12:24:28 +00:00
/** \brief Allocates memory without creating any resource placed in it.
2019-10-11 09:11:28 +00:00
This function is similar to ` ID3D12Device : : CreateHeap ` , but it may really assign
part of a larger , existing heap to the allocation .
2020-03-19 10:25:46 +00:00
If ResourceHeapTier = 1 , ` heapFlags ` must contain one of these values , depending on type
2019-10-11 09:11:28 +00:00
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 ` .
2020-03-19 10:25:46 +00:00
If ResourceHeapTier = 2 , ` heapFlags ` may be ` D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES ` = 0.
Additional flags in ` heapFlags ` are allowed as well .
2019-10-11 09:11:28 +00:00
` pAllocInfo - > SizeInBytes ` must be multiply of 64 KB .
` pAllocInfo - > Alignment ` must be one of the legal values as described in documentation of ` D3D12_HEAP_DESC ` .
2020-01-23 12:24:28 +00:00
If you use # ALLOCATION_FLAG_COMMITTED you will get a separate memory block -
a heap that always has offset 0.
2019-10-11 09:11:28 +00:00
*/
HRESULT AllocateMemory (
const ALLOCATION_DESC * pAllocDesc ,
const D3D12_RESOURCE_ALLOCATION_INFO * pAllocInfo ,
Allocation * * ppAllocation ) ;
2019-10-11 14:20:45 +00:00
/** \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 ) ;
2019-09-30 12:30:04 +00:00
/** \brief Retrieves statistics from the current state of the allocator.
*/
void CalculateStats ( Stats * pStats ) ;
2019-11-20 13:07:21 +00:00
/** \brief Retrieves information about current memory budget.
\ param [ out ] pGpuBudget Optional , can be null .
\ param [ out ] pCpuBudget Optional , can be null .
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 CalculateStats ( ) .
Note that when using allocator from multiple threads , returned information may immediately
become outdated .
*/
void GetBudget ( Budget * pGpuBudget , Budget * pCpuBudget ) ;
2019-10-11 09:11:28 +00:00
/// Builds and returns statistics as a string in JSON format.
/** @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
*/
void BuildStatsString ( WCHAR * * ppStatsString , BOOL DetailedMap ) ;
/// Frees memory of a string returned from Allocator::BuildStatsString.
void FreeStatsString ( WCHAR * pStatsString ) ;
2019-05-20 11:46:23 +00:00
private :
friend HRESULT CreateAllocator ( const ALLOCATOR_DESC * , Allocator * * ) ;
template < typename T > friend void D3D12MA_DELETE ( const ALLOCATION_CALLBACKS & , T * ) ;
Allocator ( const ALLOCATION_CALLBACKS & allocationCallbacks , const ALLOCATOR_DESC & desc ) ;
~ Allocator ( ) ;
AllocatorPimpl * m_Pimpl ;
D3D12MA_CLASS_NO_COPY ( Allocator )
} ;
/** \brief Creates new main Allocator object and returns it through `ppAllocator`.
You normally only need to call it once and keep a single Allocator object for your ` ID3D12Device ` .
*/
HRESULT CreateAllocator ( const ALLOCATOR_DESC * pDesc , Allocator * * ppAllocator ) ;
} // namespace D3D12MA
/// \cond INTERNAL
DEFINE_ENUM_FLAG_OPERATORS ( D3D12MA : : ALLOCATION_FLAGS ) ;
DEFINE_ENUM_FLAG_OPERATORS ( D3D12MA : : ALLOCATOR_FLAGS ) ;
/// \endcond