Skip to content

Commit 428e923

Browse files
committed
Add sample for Tight Aligned resources
Demonstrates the VRAM savings that the Tight Alignment feature provides compared to naive approaches to management of buffer resources. It is possible to achieve similar footprints via packing buffers together, but this feature enables you to do that without spending the effort. You also get better tooling support due to accurate resource bounds. Find out more about the Tight Alignment feature here: https://devblogs.microsoft.com/directx/agility-sdk-1-716-0-preview-tight-alignment/
1 parent 7aa2466 commit 428e923

File tree

5 files changed

+448
-22
lines changed

5 files changed

+448
-22
lines changed

Samples/Desktop/D3D12HelloWorld/src/D3D12HelloWorld.sln

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30621.155.26403.0
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.12.35707.178 d17.12
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloTriangle", "HelloTriangle\D3D12HelloTriangle.vcxproj", "{5018F6A3-6533-4744-B1FD-727D199FD2E9}"
77
EndProject
@@ -21,13 +21,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloVADecode", "Hello
2121
EndProject
2222
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloVAResourceInterop", "HelloVAResourceInterop\D3D12HelloVAResourceInterop.vcxproj", "{17171787-C5D2-4014-9D1D-BC43074F36A1}"
2323
EndProject
24-
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloWorkGraphs", "HelloWorkGraphs\D3D12HelloWorkGraphs.vcxproj", "{05080adc-d456-4058-8064-4791865f796b}"
24+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloWorkGraphs", "HelloWorkGraphs\D3D12HelloWorkGraphs.vcxproj", "{05080ADC-D456-4058-8064-4791865F796B}"
2525
EndProject
26-
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12WorkGraphsSandbox", "WorkGraphsSandbox\D3D12WorkGraphsSandbox.vcxproj", "{2725e8ec-0892-499b-acd5-0ea18157682a}"
26+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12WorkGraphsSandbox", "WorkGraphsSandbox\D3D12WorkGraphsSandbox.vcxproj", "{2725E8EC-0892-499B-ACD5-0EA18157682A}"
2727
EndProject
28-
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloGenericPrograms", "HelloGenericPrograms\D3D12HelloGenericPrograms.vcxproj", "{7db43f09-7bd6-4e69-8987-9a919a142852}"
28+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloGenericPrograms", "HelloGenericPrograms\D3D12HelloGenericPrograms.vcxproj", "{7DB43F09-7BD6-4E69-8987-9A919A142852}"
2929
EndProject
30-
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloMeshNodes", "HelloMeshNodes\D3D12HelloMeshNodes.vcxproj", "{b9680899-f009-406b-beee-d0214c1e7592}"
30+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloMeshNodes", "HelloMeshNodes\D3D12HelloMeshNodes.vcxproj", "{B9680899-F009-406B-BEEE-D0214C1E7592}"
31+
EndProject
32+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12HelloTightAlignment", "HelloTightAlignment\D3D12HelloTightAlignment.vcxproj", "{69B1A348-DF87-4335-BC68-FE8C060C7A60}"
3133
EndProject
3234
Global
3335
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -71,22 +73,26 @@ Global
7173
{17171787-C5D2-4014-9D1D-BC43074F36A1}.Debug|x64.Build.0 = Debug|x64
7274
{17171787-C5D2-4014-9D1D-BC43074F36A1}.Release|x64.ActiveCfg = Release|x64
7375
{17171787-C5D2-4014-9D1D-BC43074F36A1}.Release|x64.Build.0 = Release|x64
74-
{05080adc-d456-4058-8064-4791865f796b}.Debug|x64.ActiveCfg = Debug|x64
75-
{05080adc-d456-4058-8064-4791865f796b}.Debug|x64.Build.0 = Debug|x64
76-
{05080adc-d456-4058-8064-4791865f796b}.Release|x64.ActiveCfg = Release|x64
77-
{05080adc-d456-4058-8064-4791865f796b}.Release|x64.Build.0 = Release|x64
78-
{2725e8ec-0892-499b-acd5-0ea18157682a}.Debug|x64.ActiveCfg = Debug|x64
79-
{2725e8ec-0892-499b-acd5-0ea18157682a}.Debug|x64.Build.0 = Debug|x64
80-
{2725e8ec-0892-499b-acd5-0ea18157682a}.Release|x64.ActiveCfg = Release|x64
81-
{2725e8ec-0892-499b-acd5-0ea18157682a}.Release|x64.Build.0 = Release|x64
82-
{7db43f09-7bd6-4e69-8987-9a919a142852}.Debug|x64.ActiveCfg = Debug|x64
83-
{7db43f09-7bd6-4e69-8987-9a919a142852}.Debug|x64.Build.0 = Debug|x64
84-
{7db43f09-7bd6-4e69-8987-9a919a142852}.Release|x64.ActiveCfg = Release|x64
85-
{7db43f09-7bd6-4e69-8987-9a919a142852}.Release|x64.Build.0 = Release|x64
86-
{b9680899-f009-406b-beee-d0214c1e7592}.Debug|x64.ActiveCfg = Debug|x64
87-
{b9680899-f009-406b-beee-d0214c1e7592}.Debug|x64.Build.0 = Debug|x64
88-
{b9680899-f009-406b-beee-d0214c1e7592}.Release|x64.ActiveCfg = Release|x64
89-
{b9680899-f009-406b-beee-d0214c1e7592}.Release|x64.Build.0 = Release|x64
76+
{05080ADC-D456-4058-8064-4791865F796B}.Debug|x64.ActiveCfg = Debug|x64
77+
{05080ADC-D456-4058-8064-4791865F796B}.Debug|x64.Build.0 = Debug|x64
78+
{05080ADC-D456-4058-8064-4791865F796B}.Release|x64.ActiveCfg = Release|x64
79+
{05080ADC-D456-4058-8064-4791865F796B}.Release|x64.Build.0 = Release|x64
80+
{2725E8EC-0892-499B-ACD5-0EA18157682A}.Debug|x64.ActiveCfg = Debug|x64
81+
{2725E8EC-0892-499B-ACD5-0EA18157682A}.Debug|x64.Build.0 = Debug|x64
82+
{2725E8EC-0892-499B-ACD5-0EA18157682A}.Release|x64.ActiveCfg = Release|x64
83+
{2725E8EC-0892-499B-ACD5-0EA18157682A}.Release|x64.Build.0 = Release|x64
84+
{7DB43F09-7BD6-4E69-8987-9A919A142852}.Debug|x64.ActiveCfg = Debug|x64
85+
{7DB43F09-7BD6-4E69-8987-9A919A142852}.Debug|x64.Build.0 = Debug|x64
86+
{7DB43F09-7BD6-4E69-8987-9A919A142852}.Release|x64.ActiveCfg = Release|x64
87+
{7DB43F09-7BD6-4E69-8987-9A919A142852}.Release|x64.Build.0 = Release|x64
88+
{B9680899-F009-406B-BEEE-D0214C1E7592}.Debug|x64.ActiveCfg = Debug|x64
89+
{B9680899-F009-406B-BEEE-D0214C1E7592}.Debug|x64.Build.0 = Debug|x64
90+
{B9680899-F009-406B-BEEE-D0214C1E7592}.Release|x64.ActiveCfg = Release|x64
91+
{B9680899-F009-406B-BEEE-D0214C1E7592}.Release|x64.Build.0 = Release|x64
92+
{69B1A348-DF87-4335-BC68-FE8C060C7A60}.Debug|x64.ActiveCfg = Debug|x64
93+
{69B1A348-DF87-4335-BC68-FE8C060C7A60}.Debug|x64.Build.0 = Debug|x64
94+
{69B1A348-DF87-4335-BC68-FE8C060C7A60}.Release|x64.ActiveCfg = Release|x64
95+
{69B1A348-DF87-4335-BC68-FE8C060C7A60}.Release|x64.Build.0 = Release|x64
9096
EndGlobalSection
9197
GlobalSection(SolutionProperties) = preSolution
9298
HideSolutionNode = FALSE
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
// D3D12HelloTightAlignment.cpp : This file contains the 'main' function. Program execution begins and ends there.
2+
//
3+
4+
#include <windows.h>
5+
#include <iostream>
6+
#include <atlbase.h>
7+
#include <vector>
8+
#include <initguid.h>
9+
#include "dxcapi.h"
10+
#include "d3d12.h"
11+
#include "d3dx12.h"
12+
#include <dxgi1_6.h>
13+
14+
extern "C" { __declspec(dllexport) extern const UINT D3D12SDKVersion = 716; }
15+
extern "C" { __declspec(dllexport) extern const char* D3D12SDKPath = u8".\\D3D12\\"; }
16+
extern "C" { __declspec(dllexport) extern const char* WarpPath = u8".\\WARP\\"; }
17+
18+
// use a warp device instead of a hardware device
19+
bool g_useWarpDevice = false;
20+
21+
#pragma region helper_and_setup
22+
//=================================================================================================================================
23+
// Helper / setup code, not specific to work graphs
24+
// Look for "Start of interesting code" further below or just collapse this region.
25+
//=================================================================================================================================
26+
#define PRINT(text) std::cout << (char*)text << "\n" << std::flush;
27+
#define VERIFY_SUCCEEDED(hr) {HRESULT hrLocal = hr; if(FAILED(hrLocal)) {PRINT("Error at: " << __FILE__ << ", line: " << __LINE__ << ", HRESULT: 0x" << std::hex << hrLocal); throw E_FAIL;} }
28+
29+
struct D3DContext
30+
{
31+
CComPtr<ID3D12Device14> spDevice;
32+
CComPtr<IDXGIAdapter3> spAdapter;
33+
bool bIsHeapTier1;
34+
};
35+
36+
//=================================================================================================================================
37+
void InitDeviceAndContext(D3DContext& D3D, bool useWarp)
38+
{
39+
D3D.spDevice.Release();
40+
D3D.spAdapter.Release();
41+
42+
CComPtr<ID3D12Debug1> pDebug;
43+
VERIFY_SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pDebug)));
44+
pDebug->EnableDebugLayer();
45+
46+
D3D_FEATURE_LEVEL FL = D3D_FEATURE_LEVEL_11_0;
47+
CComPtr<ID3D12Device> spDevice;
48+
CComPtr<IDXGIFactory4> factory;
49+
VERIFY_SUCCEEDED(CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)));
50+
51+
if (useWarp)
52+
{
53+
VERIFY_SUCCEEDED(factory->EnumWarpAdapter(IID_PPV_ARGS(&D3D.spAdapter)));
54+
VERIFY_SUCCEEDED(D3D12CreateDevice(D3D.spAdapter, FL, IID_PPV_ARGS(&spDevice)));
55+
}
56+
else
57+
{
58+
VERIFY_SUCCEEDED(D3D12CreateDevice(NULL, FL, IID_PPV_ARGS(&spDevice)));
59+
LUID luid = spDevice->GetAdapterLuid();
60+
factory->EnumAdapterByLuid(luid, IID_PPV_ARGS(&D3D.spAdapter));
61+
}
62+
D3D.spDevice = spDevice;
63+
D3D.bIsHeapTier1 = false;
64+
}
65+
66+
template <UINT _Size>
67+
LPSTR FormatMemoryUsage(UINT64 usage, CHAR(&result)[_Size])
68+
{
69+
const UINT64 mb = 1 << 20;
70+
const UINT64 kb = 1 << 10;
71+
if (usage > mb)
72+
{
73+
sprintf_s(result, "%.2f MB", static_cast<float>(usage) / mb);
74+
}
75+
else if (usage > kb)
76+
{
77+
sprintf_s(result, "%.2f KB", static_cast<float>(usage) / kb);
78+
}
79+
else
80+
{
81+
sprintf_s(result, "%I64d B", usage);
82+
}
83+
return result;
84+
}
85+
86+
void PrintGPUMemoryUsage(D3DContext& D3D, UINT64 baselineUsage = 0)
87+
{
88+
DXGI_QUERY_VIDEO_MEMORY_INFO memoryInfo;
89+
D3D.spAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memoryInfo);
90+
91+
char text[100];
92+
char usageString[20];
93+
UINT64 usage = memoryInfo.CurrentUsage - baselineUsage;
94+
if (baselineUsage > memoryInfo.CurrentUsage)
95+
{
96+
PRINT(" ## Error - baseline usage was greater than current usage");
97+
return;
98+
}
99+
sprintf_s(text, " Memory Used: %s", FormatMemoryUsage(usage, usageString));
100+
PRINT(text);
101+
}
102+
103+
#pragma endregion
104+
105+
template<UINT32 numBuffers>
106+
void CreateManyPlacedBuffers(D3DContext& D3D, const CD3DX12_RESOURCE_DESC1& rDesc)
107+
{
108+
DXGI_QUERY_VIDEO_MEMORY_INFO baslineMemoryInfo;
109+
D3D.spAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &baslineMemoryInfo);
110+
111+
D3D12_RESOURCE_ALLOCATION_INFO1 infos[numBuffers];
112+
D3D12_RESOURCE_DESC1 pResourceDescs[numBuffers];
113+
std::fill_n(pResourceDescs, numBuffers, rDesc);
114+
D3D12_RESOURCE_ALLOCATION_INFO aggregateInfo = D3D.spDevice->GetResourceAllocationInfo2(0, numBuffers, pResourceDescs, infos);
115+
116+
CComPtr<ID3D12Heap> pHeap;
117+
CComPtr<ID3D12Resource> buffers[numBuffers];
118+
CD3DX12_HEAP_DESC heapDesc = CD3DX12_HEAP_DESC(aggregateInfo.SizeInBytes, D3D12_HEAP_TYPE_DEFAULT);
119+
heapDesc.Flags = D3D.bIsHeapTier1 ? D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS : D3D12_HEAP_FLAG_NONE;
120+
VERIFY_SUCCEEDED(D3D.spDevice->CreateHeap(&heapDesc, IID_PPV_ARGS(&pHeap)));
121+
for (UINT32 i = 0; i < numBuffers; i++)
122+
{
123+
VERIFY_SUCCEEDED(D3D.spDevice->CreatePlacedResource1(pHeap, infos[i].Offset, &rDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buffers[i])));
124+
}
125+
PrintGPUMemoryUsage(D3D, baslineMemoryInfo.CurrentUsage);
126+
}
127+
128+
template<UINT32 numBuffers>
129+
void ComparePlacedBufferMemoryFootprint(D3DContext& D3D)
130+
{
131+
PRINT("Comparing memory footprint for " << numBuffers << " placed buffers...\n");
132+
CD3DX12_RESOURCE_DESC1 bufferDesc;
133+
//Beyond the obvious benefits for small resources, you can also see savings for large buffers that go beyond the 64KiB mark
134+
UINT bufferSizes[] = { 1, 16, 256, 4096, 32000, 65540, 80000 };
135+
for (UINT bufferSize : bufferSizes)
136+
{
137+
PRINT("Size: " << bufferSize << " B");
138+
PRINT(" Classic buffer alignment:");
139+
bufferDesc = CD3DX12_RESOURCE_DESC1::Buffer(bufferSize);
140+
CreateManyPlacedBuffers<numBuffers>(D3D, bufferDesc);
141+
142+
PRINT(" Tight buffer alignment:");
143+
bufferDesc = CD3DX12_RESOURCE_DESC1::Buffer(bufferSize, D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT);
144+
CreateManyPlacedBuffers<numBuffers>(D3D, bufferDesc);
145+
146+
PRINT("----------");
147+
}
148+
PRINT("====================");
149+
}
150+
151+
template<UINT32 numBuffers>
152+
void CreateManyCommittedBuffers(D3DContext& D3D, const CD3DX12_RESOURCE_DESC1& rDesc)
153+
{
154+
DXGI_QUERY_VIDEO_MEMORY_INFO baslineMemoryInfo;
155+
D3D.spAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &baslineMemoryInfo);
156+
157+
CD3DX12_HEAP_PROPERTIES heapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
158+
CComPtr<ID3D12Resource> buffers[numBuffers];
159+
for (UINT32 i = 0; i < numBuffers; i++)
160+
{
161+
VERIFY_SUCCEEDED(D3D.spDevice->CreateCommittedResource2(&heapProperties, D3D12_HEAP_FLAG_NONE, &rDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, nullptr, IID_PPV_ARGS(&buffers[i])));
162+
}
163+
164+
PrintGPUMemoryUsage(D3D, baslineMemoryInfo.CurrentUsage);
165+
}
166+
167+
template<UINT32 numBuffers>
168+
void CompareCommittedBufferMemoryFootprint(D3DContext& D3D)
169+
{
170+
PRINT("Comparing memory footprint for " << numBuffers << " committed buffers...\n");
171+
CD3DX12_RESOURCE_DESC1 bufferDesc;
172+
173+
UINT bufferSizes[] = { 1, 16, 256, 4096, 65536, 65540, 80000 };
174+
for (UINT bufferSize : bufferSizes)
175+
{
176+
PRINT("Size: " << bufferSize << " B");
177+
PRINT(" Classic buffer alignment:");
178+
bufferDesc = CD3DX12_RESOURCE_DESC1::Buffer(bufferSize);
179+
CreateManyCommittedBuffers<numBuffers>(D3D, bufferDesc);
180+
181+
PRINT(" Tight buffer alignment:");
182+
bufferDesc = CD3DX12_RESOURCE_DESC1::Buffer(bufferSize, D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT);
183+
CreateManyCommittedBuffers<numBuffers>(D3D, bufferDesc);
184+
185+
PRINT("----------");
186+
}
187+
PRINT("====================");
188+
}
189+
190+
int main()
191+
{
192+
try
193+
{
194+
PRINT("\n" <<
195+
"==================================================================================\n" <<
196+
" Hello Tight Alignment\n" <<
197+
"==================================================================================");
198+
D3DContext D3D;
199+
InitDeviceAndContext(D3D, g_useWarpDevice);
200+
bool warpFallback = false;
201+
202+
CD3DX12FeatureSupport featureSupport;
203+
featureSupport.Init(D3D.spDevice);
204+
if (featureSupport.TightAlignmentSupportTier() == D3D12_TIGHT_ALIGNMENT_TIER_NOT_SUPPORTED && !g_useWarpDevice)
205+
{
206+
PRINT("Tight alignment is not supported on this driver. Retrying with Warp...");
207+
InitDeviceAndContext(D3D, true);
208+
featureSupport.Init(D3D.spDevice);
209+
warpFallback = true;
210+
}
211+
if (featureSupport.TightAlignmentSupportTier() == D3D12_TIGHT_ALIGNMENT_TIER_NOT_SUPPORTED)
212+
{
213+
PRINT("Tight alignment is not supported on this driver or the currently installed version of Warp. Aborting.");
214+
return 0;
215+
}
216+
DXGI_ADAPTER_DESC desc;
217+
VERIFY_SUCCEEDED(D3D.spAdapter->GetDesc(&desc));
218+
std::wcout << L"Running sample on " << desc.Description << L"\n\n" << std::flush;
219+
220+
D3D12_FEATURE_DATA_D3D12_OPTIONS options{};
221+
VERIFY_SUCCEEDED(D3D.spDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)));
222+
D3D.bIsHeapTier1 = options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1;
223+
224+
ComparePlacedBufferMemoryFootprint<1>(D3D); // No benefit due to the heap allocations being made in 64KiB chuncks
225+
ComparePlacedBufferMemoryFootprint<8>(D3D); // Can already see some benefit being realized
226+
ComparePlacedBufferMemoryFootprint<4096>(D3D); // drastic savings in most cases
227+
228+
PRINT("\n========================================\n========================================\n");
229+
230+
CompareCommittedBufferMemoryFootprint<1>(D3D);
231+
CompareCommittedBufferMemoryFootprint<8>(D3D);
232+
CompareCommittedBufferMemoryFootprint<4096>(D3D);
233+
}
234+
catch (HRESULT)
235+
{
236+
PRINT("Aborting.");
237+
return -1;
238+
}
239+
return 0;
240+
241+
}

0 commit comments

Comments
 (0)