Skip to content

Commit cdf948b

Browse files
Added support for resource tight alignment
Added macro D3D12MA_TIGHT_ALIGNMENT_SUPPORTED, flag ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT, function Allocator::IsTightAlignmentSupported.
1 parent 1509c78 commit cdf948b

5 files changed

Lines changed: 131 additions & 7 deletions

File tree

include/D3D12MemAlloc.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,8 @@ enum ALLOCATOR_FLAGS
10531053
It can also be disabled for a single allocation by using #ALLOCATION_FLAG_STRATEGY_MIN_TIME.
10541054
*/
10551055
ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED = 0x10,
1056+
/** TODO document... */
1057+
ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT = 0x20,
10561058
};
10571059

10581060
/// \brief Parameters of created Allocator object. To be used with CreateAllocator().
@@ -1127,6 +1129,15 @@ class D3D12MA_API Allocator : public IUnknownImpl
11271129
`#define D3D12MA_OPTIONS16_SUPPORTED 1` is needed for the compilation of this library. Otherwise the flag is always false.
11281130
*/
11291131
BOOL IsGPUUploadHeapSupported() const;
1132+
/** \brief Returns true if resource tight alignment is supported on the current system.
1133+
When supported, it is automatically used by the library, unless
1134+
#ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT flag was specified on allocator creation.
1135+
1136+
This flag is fetched from `D3D12_FEATURE_DATA_TIGHT_ALIGNMENT::SupportTier`.
1137+
1138+
`#define D3D12MA_TIGHT_ALIGNMENT_SUPPORTED 1` is needed for the compilation of this library. Otherwise the flag is always false.
1139+
*/
1140+
BOOL IsTightAlignmentSupported() const;
11301141
/** \brief Returns total amount of memory of specific segment group, in bytes.
11311142
11321143
\param memorySegmentGroup use `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` or DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`.

src/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,11 @@ if(D3D12MA_OPTIONS16_SUPPORTED)
198198
target_compile_definitions(D3D12Sample PRIVATE D3D12MA_OPTIONS16_SUPPORTED=1)
199199
endif()
200200
endif()
201+
202+
option(D3D12MA_TIGHT_ALIGNMENT_SUPPORTED "Set if using Agility SDK 1.716.0-preview or newer that defines D3D12_FEATURE_DATA_TIGHT_ALIGNMENT." OFF)
203+
if(D3D12MA_TIGHT_ALIGNMENT_SUPPORTED)
204+
target_compile_definitions(D3D12MemoryAllocator PRIVATE D3D12MA_TIGHT_ALIGNMENT_SUPPORTED=1)
205+
if(${D3D12MA_BUILD_SAMPLE} AND ${WIN32})
206+
target_compile_definitions(D3D12Sample PRIVATE D3D12MA_TIGHT_ALIGNMENT_SUPPORTED=1)
207+
endif()
208+
endif()

src/D3D12MemAlloc.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5911,6 +5911,8 @@ class AllocatorPimpl
59115911
BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
59125912
bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
59135913
bool IsGPUUploadHeapSupported() const { return m_GPUUploadHeapSupported != FALSE; }
5914+
bool IsTightAlignmentSupported() const { return m_TightAlignmentSupported != FALSE; }
5915+
bool IsTightAlignmentEnabled() const { return IsTightAlignmentSupported() && m_UseTightAlignment; }
59145916
bool UseMutex() const { return m_UseMutex; }
59155917
AllocationObjectAllocator& GetAllocationObjectAllocator() { return m_AllocationObjectAllocator; }
59165918
UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
@@ -5998,6 +6000,7 @@ class AllocatorPimpl
59986000
const bool m_AlwaysCommitted;
59996001
const bool m_MsaaAlwaysCommitted;
60006002
const bool m_PreferSmallBuffersCommitted;
6003+
const bool m_UseTightAlignment;
60016004
bool m_DefaultPoolsNotZeroed = false;
60026005
ID3D12Device* m_Device; // AddRef
60036006
#ifdef __ID3D12Device1_INTERFACE_DEFINED__
@@ -6022,6 +6025,7 @@ class AllocatorPimpl
60226025
DXGI_ADAPTER_DESC m_AdapterDesc;
60236026
D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
60246027
BOOL m_GPUUploadHeapSupported = FALSE;
6028+
BOOL m_TightAlignmentSupported = FALSE;
60256029
D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
60266030
AllocationObjectAllocator m_AllocationObjectAllocator;
60276031

@@ -6089,7 +6093,8 @@ AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks,
60896093
: m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
60906094
m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0),
60916095
m_MsaaAlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0),
6092-
m_PreferSmallBuffersCommitted((desc.Flags & ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED) == 0),
6096+
m_PreferSmallBuffersCommitted((desc.Flags& ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED) == 0),
6097+
m_UseTightAlignment((desc.Flags & ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT) == 0),
60936098
m_Device(desc.pDevice),
60946099
m_Adapter(desc.pAdapter),
60956100
m_PreferredBlockSize(desc.PreferredBlockSize != 0 ? desc.PreferredBlockSize : D3D12MA_DEFAULT_BLOCK_SIZE),
@@ -6177,6 +6182,20 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
61776182
}
61786183
#endif
61796184

6185+
// You must define macro `#define D3D12MA_TIGHT_ALIGNMENT_SUPPORTED 1` to enable resource tight alignment!
6186+
// Unfortunately there is no way to programmatically check if the included <d3d12.h> defines D3D12_FEATURE_DATA_TIGHT_ALIGNMENT or not.
6187+
// Main interfaces have respective macros like __ID3D12Device4_INTERFACE_DEFINED__, but structures like this do not.
6188+
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
6189+
{
6190+
D3D12_FEATURE_DATA_TIGHT_ALIGNMENT tightAlignment = {};
6191+
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_TIGHT_ALIGNMENT, &tightAlignment, sizeof(tightAlignment));
6192+
if (SUCCEEDED(hr))
6193+
{
6194+
m_TightAlignmentSupported = tightAlignment.SupportTier >= D3D12_TIGHT_ALIGNMENT_TIER_1;
6195+
}
6196+
}
6197+
#endif
6198+
61806199
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &m_D3D12Architecture, sizeof(m_D3D12Architecture));
61816200
if (FAILED(hr))
61826201
{
@@ -6861,6 +6880,9 @@ void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap)
68616880

68626881
json.WriteString(L"GPUUploadHeapSupported");
68636882
json.WriteBool(m_GPUUploadHeapSupported != FALSE);
6883+
6884+
json.WriteString(L"TightAlignmentSupported");
6885+
json.WriteBool(m_TightAlignmentSupported != FALSE);
68646886
}
68656887
json.EndObject();
68666888
}
@@ -7623,21 +7645,34 @@ template<typename D3D12_RESOURCE_DESC_T>
76237645
D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const
76247646
{
76257647
#ifdef __ID3D12Device1_INTERFACE_DEFINED__
7626-
/* Optional optimization: Microsoft documentation says:
7627-
https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getresourceallocationinfo
7648+
7649+
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
7650+
if (IsTightAlignmentEnabled() &&
7651+
// Don't allow USE_TIGHT_ALIGNMENT together with ALLOW_CROSS_ADAPTER as there is a D3D Debug Layer error:
7652+
// D3D12 ERROR: ID3D12Device::GetResourceAllocationInfo: D3D12_RESOURCE_DESC::Flag D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT will be ignored since D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER is set. [ STATE_CREATION ERROR #599: CREATERESOURCE_INVALIDMISCFLAGS]
7653+
(inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER) == 0)
7654+
{
7655+
inOutResourceDesc.Flags |= D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT;
7656+
}
7657+
#endif // #if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
7658+
7659+
/* Optional optimization: Microsoft documentation of the ID3D12Device::
7660+
GetResourceAllocationInfo function says:
76287661
76297662
Your application can forgo using GetResourceAllocationInfo for buffer resources
76307663
(D3D12_RESOURCE_DIMENSION_BUFFER). Buffers have the same size on all adapters,
76317664
which is merely the smallest multiple of 64KB that's greater or equal to
76327665
D3D12_RESOURCE_DESC::Width.
76337666
*/
76347667
if (inOutResourceDesc.Alignment == 0 &&
7635-
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
7668+
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
7669+
!IsTightAlignmentEnabled())
76367670
{
76377671
return {
76387672
AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
76397673
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT }; // Alignment
76407674
}
7675+
76417676
#endif // #ifdef __ID3D12Device1_INTERFACE_DEFINED__
76427677

76437678
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
@@ -9552,6 +9587,11 @@ BOOL Allocator::IsGPUUploadHeapSupported() const
95529587
return m_Pimpl->IsGPUUploadHeapSupported();
95539588
}
95549589

9590+
BOOL Allocator::IsTightAlignmentSupported() const
9591+
{
9592+
return m_Pimpl->IsTightAlignmentSupported();
9593+
}
9594+
95559595
UINT64 Allocator::GetMemoryCapacity(UINT memorySegmentGroup) const
95569596
{
95579597
return m_Pimpl->GetMemoryCapacity(memorySegmentGroup);

src/D3D12Sample.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,11 @@ inline UINT64 UpdateSubresources(
438438
UINT* pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
439439

440440
D3D12_RESOURCE_DESC Desc = pDestinationResource->GetDesc();
441+
442+
// Needed because of the D3D Debug Layer error:
443+
// D3D12 ERROR: ID3D12Device::GetCopyableFootprints: D3D12_RESOURCE_DESC::Alignment is invalid. The value is 16. When D3D12_RESOURCE_DESC::Flag bit for D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT is set, Alignment must be 0. [ STATE_CREATION ERROR #721: CREATERESOURCE_INVALIDALIGNMENT]
444+
Desc.Alignment = 0;
445+
441446
ID3D12Device* pDevice;
442447
pDestinationResource->GetDevice(__uuidof(*pDevice), reinterpret_cast<void**>(&pDevice));
443448
pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
@@ -1052,8 +1057,7 @@ static void InitD3D() // initializes direct3d 12
10521057
CHECK_HR( g_Allocator->CreateResource(
10531058
&vertexBufferAllocDesc,
10541059
&vertexBufferResourceDesc, // resource description for a buffer
1055-
D3D12_RESOURCE_STATE_COPY_DEST, // we will start this heap in the copy destination state since we will copy data
1056-
// from the upload heap to this heap
1060+
D3D12_RESOURCE_STATE_COMMON,
10571061
nullptr, // optimized clear value must be null for this type of resource. used for render targets and depth/stencil buffers
10581062
&g_VertexBufferAllocation,
10591063
IID_PPV_ARGS(&vertexBufferPtr)) );
@@ -1165,7 +1169,7 @@ static void InitD3D() // initializes direct3d 12
11651169
CHECK_HR( g_Allocator->CreateResource(
11661170
&indexBufferAllocDesc,
11671171
&indexBufferResourceDesc, // resource description for a buffer
1168-
D3D12_RESOURCE_STATE_COPY_DEST, // start in the copy destination state
1172+
D3D12_RESOURCE_STATE_COMMON,
11691173
nullptr, // optimized clear value must be null for this type of resource
11701174
&g_IndexBufferAllocation,
11711175
IID_PPV_ARGS(&g_IndexBuffer)) );

src/Tests.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ static constexpr UINT64 MEGABYTE = 1024 * KILOBYTE;
5151
static constexpr CONFIG_TYPE ConfigType = CONFIG_TYPE_AVERAGE;
5252
static const char* FREE_ORDER_NAMES[] = { "FORWARD", "BACKWARD", "RANDOM", };
5353

54+
// Indexes match enum D3D12_HEAP_TYPE.
55+
static const WCHAR* const HEAP_TYPE_NAMES[] =
56+
{
57+
L"",
58+
L"DEFAULT",
59+
L"UPLOAD",
60+
L"READBACK",
61+
L"CUSTOM",
62+
L"GPU_UPLOAD",
63+
};
64+
5465
static void CurrentTimeToStr(std::string& out)
5566
{
5667
time_t rawTime; time(&rawTime);
@@ -2990,6 +3001,55 @@ static void TestGPUUploadHeap(const TestContext& ctx)
29903001
#endif
29913002
}
29923003

3004+
static void TestTightAlignment(const TestContext& ctx)
3005+
{
3006+
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
3007+
using namespace D3D12MA;
3008+
3009+
wprintf(L"Test resource tight alignment\n");
3010+
3011+
if(!ctx.allocator->IsTightAlignmentSupported())
3012+
{
3013+
wprintf(L" Skipped due to tight alignment not supported.\n");
3014+
return;
3015+
}
3016+
3017+
// Use a custom heap to make sure our small buffers are not created as committed.
3018+
POOL_DESC poolDesc = {};
3019+
poolDesc.BlockSize = 1024 * 1024;
3020+
poolDesc.MinBlockCount = poolDesc.MaxBlockCount = 1;
3021+
3022+
D3D12_RESOURCE_DESC resDesc;
3023+
FillResourceDescForBuffer(resDesc, 16);
3024+
3025+
const D3D12_HEAP_TYPE heapTypes[] = { D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_TYPE_UPLOAD };
3026+
for (auto heapType : heapTypes)
3027+
{
3028+
poolDesc.HeapProperties.Type = heapType;
3029+
ComPtr<Pool> pool;
3030+
CHECK_HR(ctx.allocator->CreatePool(&poolDesc, &pool));
3031+
3032+
ALLOCATION_DESC allocDesc = {};
3033+
allocDesc.CustomPool = pool.Get();
3034+
3035+
ComPtr<Allocation> allocs[2] = {};
3036+
3037+
for (size_t i = 0; i < _countof(allocs); ++i)
3038+
{
3039+
CHECK_HR(ctx.allocator->CreateResource(&allocDesc, &resDesc,
3040+
D3D12_RESOURCE_STATE_COMMON, NULL, &allocs[i], IID_NULL, NULL));
3041+
CHECK_BOOL(allocs[i] && allocs[i]->GetResource());
3042+
}
3043+
3044+
// Print the offset of the 2nd buffer.
3045+
wprintf(L" In D3D12_HEAP_TYPE_%s, a %llu B buffer was aligned to %llu B.\n",
3046+
HEAP_TYPE_NAMES[(size_t)heapType],
3047+
resDesc.Width,
3048+
allocs[1]->GetOffset());
3049+
}
3050+
#endif
3051+
}
3052+
29933053
static void TestVirtualBlocks(const TestContext& ctx)
29943054
{
29953055
wprintf(L"Test virtual blocks\n");
@@ -4257,6 +4317,7 @@ static void TestGroupBasics(const TestContext& ctx)
42574317
#endif
42584318

42594319
TestGPUUploadHeap(ctx);
4320+
TestTightAlignment(ctx);
42604321

42614322
FILE* file;
42624323
fopen_s(&file, "Results.csv", "w");

0 commit comments

Comments
 (0)