@@ -10,6 +10,23 @@ using namespace Windows::UI::Core;
10
10
using namespace Windows ::UI::Xaml::Controls;
11
11
using namespace Platform ;
12
12
13
+ namespace DisplayMetrics
14
+ {
15
+ // High resolution displays can require a lot of GPU and battery power to render.
16
+ // High resolution phones, for example, may suffer from poor battery life if
17
+ // games attempt to render at 60 frames per second at full fidelity.
18
+ // The decision to render at full fidelity across all platforms and form factors
19
+ // should be deliberate.
20
+ static const bool SupportHighResolutions = false ;
21
+
22
+ // The default thresholds that define a "high resolution" display. If the thresholds
23
+ // are exceeded and SupportHighResolutions is false, the dimensions will be scaled
24
+ // by 50%.
25
+ static const float DpiThreshold = 192 .0f ; // 200% of standard desktop display.
26
+ static const float WidthThreshold = 1920 .0f ; // 1080p width.
27
+ static const float HeightThreshold = 1080 .0f ; // 1080p height.
28
+ };
29
+
13
30
// Constants used to calculate screen rotations.
14
31
namespace ScreenRotation
15
32
{
@@ -58,6 +75,7 @@ DX::DeviceResources::DeviceResources() :
58
75
m_nativeOrientation(DisplayOrientations::None),
59
76
m_currentOrientation(DisplayOrientations::None),
60
77
m_dpi(-1 .0f ),
78
+ m_effectiveDpi(-1 .0f ),
61
79
m_deviceRemoved(false )
62
80
{
63
81
ZeroMemory (m_fenceValues, sizeof (m_fenceValues));
@@ -86,9 +104,12 @@ void DX::DeviceResources::CreateDeviceResources()
86
104
87
105
DX::ThrowIfFailed (CreateDXGIFactory1 (IID_PPV_ARGS (&m_dxgiFactory)));
88
106
107
+ ComPtr<IDXGIAdapter1> adapter;
108
+ GetHardwareAdapter (m_dxgiFactory.Get (), &adapter);
109
+
89
110
// Create the Direct3D 12 API device object
90
111
HRESULT hr = D3D12CreateDevice (
91
- nullptr , // Specify nullptr to use the default adapter.
112
+ adapter. Get () , // The hardware adapter.
92
113
D3D_FEATURE_LEVEL_11_0, // Minimum feature level this app can support.
93
114
IID_PPV_ARGS (&m_d3dDevice) // Returns the Direct3D device created.
94
115
);
@@ -145,13 +166,7 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
145
166
}
146
167
m_rtvHeap = nullptr ;
147
168
148
- // Calculate the necessary render target size in pixels.
149
- m_outputSize.Width = DX::ConvertDipsToPixels (m_logicalSize.Width , m_dpi);
150
- m_outputSize.Height = DX::ConvertDipsToPixels (m_logicalSize.Height , m_dpi);
151
-
152
- // Prevent zero size DirectX content from being created.
153
- m_outputSize.Width = max (m_outputSize.Width , 1 );
154
- m_outputSize.Height = max (m_outputSize.Height , 1 );
169
+ UpdateRenderTargetSize ();
155
170
156
171
// The width and height of the swap chain must be based on the window's
157
172
// natively-oriented width and height. If the window is not in the native
@@ -189,6 +204,7 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
189
204
else
190
205
{
191
206
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
207
+ DXGI_SCALING scaling = DisplayMetrics::SupportHighResolutions ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
192
208
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
193
209
194
210
swapChainDesc.Width = lround (m_d3dRenderTargetSize.Width ); // Match the size of the window.
@@ -201,13 +217,13 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
201
217
swapChainDesc.BufferCount = c_frameCount; // Use triple-buffering to minimize latency.
202
218
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // All Windows Universal apps must use _FLIP_ SwapEffects
203
219
swapChainDesc.Flags = 0 ;
204
- swapChainDesc.Scaling = DXGI_SCALING_NONE ;
220
+ swapChainDesc.Scaling = scaling ;
205
221
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
206
222
207
223
ComPtr<IDXGISwapChain1> swapChain;
208
224
DX::ThrowIfFailed (
209
225
m_dxgiFactory->CreateSwapChainForCoreWindow (
210
- m_commandQueue.Get (),
226
+ m_commandQueue.Get (), // Swap chains need a reference to the command queue in DirectX 12.
211
227
reinterpret_cast <IUnknown*>(m_window.Get ()),
212
228
&swapChainDesc,
213
229
nullptr ,
@@ -248,22 +264,15 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
248
264
m_swapChain->SetRotation (displayRotation)
249
265
);
250
266
251
- // Create a render target view of the swap chain back buffer.
267
+ // Create render target views of the swap chain back buffer.
252
268
{
253
- D3D12_DESCRIPTOR_HEAP_DESC desc = {};
254
- desc .NumDescriptors = c_frameCount;
255
- desc .Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
256
- desc .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
257
- DX::ThrowIfFailed (m_d3dDevice->CreateDescriptorHeap (&desc , IID_PPV_ARGS (&m_rtvHeap)));
269
+ D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
270
+ rtvHeapDesc .NumDescriptors = c_frameCount;
271
+ rtvHeapDesc .Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
272
+ rtvHeapDesc .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
273
+ DX::ThrowIfFailed (m_d3dDevice->CreateDescriptorHeap (&rtvHeapDesc , IID_PPV_ARGS (&m_rtvHeap)));
258
274
m_rtvHeap->SetName (L" Render Target View Descriptor Heap" );
259
275
260
- // All pending GPU work was already finished. Update the tracked fence values
261
- // to the last value signaled.
262
- for (UINT n = 0 ; n < c_frameCount; n++)
263
- {
264
- m_fenceValues[n] = m_fenceValues[m_currentFrame];
265
- }
266
-
267
276
m_currentFrame = 0 ;
268
277
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor (m_rtvHeap->GetCPUDescriptorHandleForHeapStart ());
269
278
m_rtvDescriptorSize = m_d3dDevice->GetDescriptorHandleIncrementSize (D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
@@ -279,10 +288,85 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
279
288
}
280
289
}
281
290
291
+ // Create a depth stencil view.
292
+ {
293
+ D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
294
+ dsvHeapDesc.NumDescriptors = 1 ;
295
+ dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
296
+ dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
297
+ ThrowIfFailed (m_d3dDevice->CreateDescriptorHeap (&dsvHeapDesc, IID_PPV_ARGS (&m_dsvHeap)));
298
+
299
+ D3D12_HEAP_PROPERTIES depthHeapProperties = CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT);
300
+ D3D12_RESOURCE_DESC depthResourceDesc = CD3DX12_RESOURCE_DESC::Tex2D (
301
+ DXGI_FORMAT_D32_FLOAT,
302
+ static_cast <UINT>(m_d3dRenderTargetSize.Width ),
303
+ static_cast <UINT>(m_d3dRenderTargetSize.Height ),
304
+ 1 ,
305
+ 0 ,
306
+ 1 ,
307
+ 0 ,
308
+ D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
309
+
310
+ D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
311
+ depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
312
+ depthOptimizedClearValue.DepthStencil .Depth = 1 .0f ;
313
+ depthOptimizedClearValue.DepthStencil .Stencil = 0 ;
314
+
315
+ ThrowIfFailed (m_d3dDevice->CreateCommittedResource (
316
+ &depthHeapProperties,
317
+ D3D12_HEAP_FLAG_NONE,
318
+ &depthResourceDesc,
319
+ D3D12_RESOURCE_STATE_DEPTH_WRITE,
320
+ &depthOptimizedClearValue,
321
+ IID_PPV_ARGS (&m_depthStencil)
322
+ ));
323
+
324
+ D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
325
+ dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
326
+ dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
327
+ dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
328
+
329
+ m_d3dDevice->CreateDepthStencilView (m_depthStencil.Get (), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart ());
330
+ }
331
+
332
+ // All pending GPU work was already finished. Update the tracked fence values
333
+ // to the last value signaled.
334
+ for (UINT n = 0 ; n < c_frameCount; n++)
335
+ {
336
+ m_fenceValues[n] = m_fenceValues[m_currentFrame];
337
+ }
338
+
282
339
// Set the 3D rendering viewport to target the entire window.
283
340
m_screenViewport = { 0 .0f , 0 .0f , m_d3dRenderTargetSize.Width , m_d3dRenderTargetSize.Height , 0 .0f , 1 .0f };
284
341
}
285
342
343
+ void DX::DeviceResources::UpdateRenderTargetSize ()
344
+ {
345
+ m_effectiveDpi = m_dpi;
346
+
347
+ // To improve battery life on high resolution devices, render to a smaller render target
348
+ // and allow the GPU to scale the output when it is presented.
349
+ if (!DisplayMetrics::SupportHighResolutions && m_dpi > DisplayMetrics::DpiThreshold)
350
+ {
351
+ float width = DX::ConvertDipsToPixels (m_logicalSize.Width , m_dpi);
352
+ float height = DX::ConvertDipsToPixels (m_logicalSize.Height , m_dpi);
353
+
354
+ if (width > DisplayMetrics::WidthThreshold && height > DisplayMetrics::HeightThreshold)
355
+ {
356
+ // To scale the app we change the effective DPI. Logical size does not change.
357
+ m_effectiveDpi /= 2 .0f ;
358
+ }
359
+ }
360
+
361
+ // Calculate the necessary render target size in pixels.
362
+ m_outputSize.Width = DX::ConvertDipsToPixels (m_logicalSize.Width , m_effectiveDpi);
363
+ m_outputSize.Height = DX::ConvertDipsToPixels (m_logicalSize.Height , m_effectiveDpi);
364
+
365
+ // Prevent zero size DirectX content from being created.
366
+ m_outputSize.Width = max (m_outputSize.Width , 1 );
367
+ m_outputSize.Height = max (m_outputSize.Height , 1 );
368
+ }
369
+
286
370
// This method is called when the CoreWindow is created (or re-created).
287
371
void DX::DeviceResources::SetWindow (CoreWindow^ window)
288
372
{
@@ -473,4 +557,33 @@ DXGI_MODE_ROTATION DX::DeviceResources::ComputeDisplayRotation()
473
557
break ;
474
558
}
475
559
return rotation;
476
- }
560
+ }
561
+
562
+ // This method acquires the first available hardware adapter that supports Direct3D 12.
563
+ // If no such adapter can be found, *ppAdapter will be set to nullptr.
564
+ void DX::DeviceResources::GetHardwareAdapter (IDXGIFactory4* pFactory, IDXGIAdapter1** ppAdapter)
565
+ {
566
+ ComPtr<IDXGIAdapter1> adapter;
567
+ *ppAdapter = nullptr ;
568
+
569
+ for (UINT adapterIndex = 0 ; DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1 (adapterIndex, &adapter); ++adapterIndex)
570
+ {
571
+ DXGI_ADAPTER_DESC1 desc;
572
+ adapter->GetDesc1 (&desc);
573
+
574
+ if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
575
+ {
576
+ // Don't select the Basic Render Driver adapter.
577
+ continue ;
578
+ }
579
+
580
+ // Check to see if the adapter supports Direct3D 12, but don't create the
581
+ // actual device yet.
582
+ if (SUCCEEDED (D3D12CreateDevice (adapter.Get (), D3D_FEATURE_LEVEL_11_0, _uuidof (ID3D12Device), nullptr )))
583
+ {
584
+ break ;
585
+ }
586
+ }
587
+
588
+ *ppAdapter = adapter.Detach ();
589
+ }
0 commit comments