CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/UWP/Common/DeviceResources.cpp
Views: 1401
1
#include "pch.h"
2
#include <algorithm>
3
#include "DeviceResources.h"
4
#include "DirectXHelper.h"
5
6
#include "Core/Config.h"
7
#include "Common/StringUtils.h"
8
#include "Common/Data/Encoding/Utf8.h"
9
10
using namespace D2D1;
11
using namespace DirectX;
12
using namespace Microsoft::WRL;
13
using namespace Windows::Foundation;
14
using namespace Windows::Graphics::Display;
15
using namespace Windows::UI::Core;
16
using namespace Windows::UI::Xaml::Controls;
17
using namespace Platform;
18
19
namespace DisplayMetrics
20
{
21
// High resolution displays can require a lot of GPU and battery power to render.
22
// High resolution phones, for example, may suffer from poor battery life if
23
// games attempt to render at 60 frames per second at full fidelity.
24
// The decision to render at full fidelity across all platforms and form factors
25
// should be deliberate.
26
static const bool SupportHighResolutions = true;
27
28
// The default thresholds that define a "high resolution" display. If the thresholds
29
// are exceeded and SupportHighResolutions is false, the dimensions will be scaled
30
// by 50%.
31
static const float DpiThreshold = 192.0f; // 200% of standard desktop display.
32
static const float WidthThreshold = 1920.0f; // 1080p width.
33
static const float HeightThreshold = 1080.0f; // 1080p height.
34
};
35
36
// Constants used to calculate screen rotations
37
namespace ScreenRotation
38
{
39
// 0-degree Z-rotation
40
static const XMFLOAT4X4 Rotation0(
41
1.0f, 0.0f, 0.0f, 0.0f,
42
0.0f, 1.0f, 0.0f, 0.0f,
43
0.0f, 0.0f, 1.0f, 0.0f,
44
0.0f, 0.0f, 0.0f, 1.0f
45
);
46
47
// 90-degree Z-rotation
48
static const XMFLOAT4X4 Rotation90(
49
0.0f, 1.0f, 0.0f, 0.0f,
50
-1.0f, 0.0f, 0.0f, 0.0f,
51
0.0f, 0.0f, 1.0f, 0.0f,
52
0.0f, 0.0f, 0.0f, 1.0f
53
);
54
55
// 180-degree Z-rotation
56
static const XMFLOAT4X4 Rotation180(
57
-1.0f, 0.0f, 0.0f, 0.0f,
58
0.0f, -1.0f, 0.0f, 0.0f,
59
0.0f, 0.0f, 1.0f, 0.0f,
60
0.0f, 0.0f, 0.0f, 1.0f
61
);
62
63
// 270-degree Z-rotation
64
static const XMFLOAT4X4 Rotation270(
65
0.0f, -1.0f, 0.0f, 0.0f,
66
1.0f, 0.0f, 0.0f, 0.0f,
67
0.0f, 0.0f, 1.0f, 0.0f,
68
0.0f, 0.0f, 0.0f, 1.0f
69
);
70
};
71
72
// Constructor for DeviceResources.
73
DX::DeviceResources::DeviceResources() :
74
m_screenViewport(),
75
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
76
m_d3dRenderTargetSize(),
77
m_outputSize(),
78
m_logicalSize(),
79
m_nativeOrientation(DisplayOrientations::None),
80
m_currentOrientation(DisplayOrientations::None),
81
m_dpi(-1.0f),
82
m_effectiveDpi(-1.0f),
83
m_deviceNotify(nullptr)
84
{
85
CreateDeviceIndependentResources();
86
CreateDeviceResources();
87
}
88
89
// Configures resources that don't depend on the Direct3D device.
90
void DX::DeviceResources::CreateDeviceIndependentResources()
91
{
92
// Initialize Direct2D resources.
93
D2D1_FACTORY_OPTIONS options;
94
ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
95
96
#if defined(_DEBUG)
97
// If the project is in a debug build, enable Direct2D debugging via SDK Layers.
98
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
99
#endif
100
101
// Initialize the Direct2D Factory.
102
DX::ThrowIfFailed(
103
D2D1CreateFactory(
104
D2D1_FACTORY_TYPE_SINGLE_THREADED,
105
__uuidof(ID2D1Factory3),
106
&options,
107
&m_d2dFactory
108
)
109
);
110
111
// Initialize the DirectWrite Factory.
112
DX::ThrowIfFailed(
113
DWriteCreateFactory(
114
DWRITE_FACTORY_TYPE_SHARED,
115
__uuidof(IDWriteFactory3),
116
&m_dwriteFactory
117
)
118
);
119
120
// Initialize the Windows Imaging Component (WIC) Factory.
121
DX::ThrowIfFailed(
122
CoCreateInstance(
123
CLSID_WICImagingFactory2,
124
nullptr,
125
CLSCTX_INPROC_SERVER,
126
IID_PPV_ARGS(&m_wicFactory)
127
)
128
);
129
}
130
131
// Configures the Direct3D device, and stores handles to it and the device context.
132
void DX::DeviceResources::CreateDeviceResources(IDXGIAdapter* vAdapter)
133
{
134
// This flag adds support for surfaces with a different color channel ordering
135
// than the API default. It is required for compatibility with Direct2D.
136
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
137
138
#if defined(_DEBUG)
139
if (DX::SdkLayersAvailable())
140
{
141
// If the project is in a debug build, enable debugging via SDK Layers with this flag.
142
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
143
}
144
#endif
145
146
// This array defines the set of DirectX hardware feature levels this app will support.
147
// Note the ordering should be preserved.
148
// Don't forget to declare your application's minimum required feature level in its
149
// description. All applications are assumed to support 9.1 unless otherwise stated.
150
D3D_FEATURE_LEVEL featureLevels[] =
151
{
152
D3D_FEATURE_LEVEL_12_1,
153
D3D_FEATURE_LEVEL_12_0,
154
D3D_FEATURE_LEVEL_11_1,
155
D3D_FEATURE_LEVEL_11_0,
156
D3D_FEATURE_LEVEL_10_1,
157
D3D_FEATURE_LEVEL_10_0,
158
D3D_FEATURE_LEVEL_9_3,
159
D3D_FEATURE_LEVEL_9_2,
160
D3D_FEATURE_LEVEL_9_1
161
};
162
163
// Create the Direct3D 11 API device object and a corresponding context.
164
ComPtr<ID3D11Device> device;
165
ComPtr<ID3D11DeviceContext> context;
166
auto hardwareType = (vAdapter != nullptr ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE);
167
HRESULT hr = D3D11CreateDevice(
168
vAdapter, // Specify nullptr to use the default adapter.
169
hardwareType, // Create a device using the hardware graphics driver.
170
0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE.
171
creationFlags, // Set debug and Direct2D compatibility flags.
172
featureLevels, // List of feature levels this app can support.
173
ARRAYSIZE(featureLevels), // Size of the list above.
174
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
175
&device, // Returns the Direct3D device created.
176
&m_d3dFeatureLevel, // Returns feature level of device created.
177
&context // Returns the device immediate context.
178
);
179
180
if (FAILED(hr))
181
{
182
// If the initialization fails, fall back to the WARP device.
183
// For more information on WARP, see:
184
// http://go.microsoft.com/fwlink/?LinkId=286690
185
DX::ThrowIfFailed(
186
D3D11CreateDevice(
187
nullptr,
188
D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device.
189
0,
190
creationFlags,
191
featureLevels,
192
ARRAYSIZE(featureLevels),
193
D3D11_SDK_VERSION,
194
&device,
195
&m_d3dFeatureLevel,
196
&context
197
)
198
);
199
}
200
201
if (!vAdapter && CreateAdaptersList(device)) {
202
// While fetching the adapters list
203
// we will check if the configs has custom adapter
204
// then will recall this function to create device with custom adapter
205
// so we have to stop here, if the `CreateAdaptersList` return true
206
return;
207
}
208
209
// Store pointers to the Direct3D 11.3 API device and immediate context.
210
DX::ThrowIfFailed(
211
device.As(&m_d3dDevice)
212
);
213
214
DX::ThrowIfFailed(
215
context.As(&m_d3dContext)
216
);
217
218
DX::ThrowIfFailed(
219
m_d3dDevice.As(&m_dxgiDevice)
220
);
221
222
DX::ThrowIfFailed(
223
m_dxgiDevice->GetAdapter(&m_dxgiAdapter)
224
);
225
226
DX::ThrowIfFailed(
227
m_dxgiAdapter->GetParent(IID_PPV_ARGS(&m_dxgiFactory))
228
);
229
230
// Create the Direct2D device object and a corresponding context.
231
DX::ThrowIfFailed(
232
m_d3dDevice.As(&m_dxgiDevice)
233
);
234
235
DX::ThrowIfFailed(
236
m_d2dFactory->CreateDevice(m_dxgiDevice.Get(), &m_d2dDevice)
237
);
238
239
DX::ThrowIfFailed(
240
m_d2dDevice->CreateDeviceContext(
241
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
242
&m_d2dContext
243
)
244
);
245
}
246
247
bool DX::DeviceResources::CreateAdaptersList(ComPtr<ID3D11Device> device) {
248
ComPtr<IDXGIDevice3> dxgi_device;
249
DX::ThrowIfFailed(
250
device.As(&dxgi_device)
251
);
252
253
Microsoft::WRL::ComPtr<IDXGIAdapter> deviceAdapter;
254
dxgi_device->GetAdapter(&deviceAdapter);
255
256
Microsoft::WRL::ComPtr<IDXGIFactory4> deviceFactory;
257
deviceAdapter->GetParent(IID_PPV_ARGS(&deviceFactory));
258
259
// Current adapter (Get current adapter name)
260
DXGI_ADAPTER_DESC currentDefaultAdapterDesc;
261
deviceAdapter->GetDesc(&currentDefaultAdapterDesc);
262
std::string currentDefaultAdapterName = ConvertWStringToUTF8(currentDefaultAdapterDesc.Description);
263
264
UINT i = 0;
265
IDXGIAdapter* pAdapter;
266
IDXGIAdapter* customAdapter = nullptr;
267
auto deviceInfo = Windows::System::Profile::AnalyticsInfo::VersionInfo;
268
bool isXbox = deviceInfo->DeviceFamily == "Windows.Xbox";
269
while (deviceFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND)
270
{
271
++i;
272
DXGI_ADAPTER_DESC vAdapterDesc;
273
pAdapter->GetDesc(&vAdapterDesc);
274
auto adapterDescription = ConvertWStringToUTF8(vAdapterDesc.Description);
275
if (isXbox && adapterDescription == "Microsoft Basic Render Driver") {
276
// Skip, very slow and not usefull for Xbox
277
continue;
278
}
279
m_vAdapters.push_back(adapterDescription);
280
if (!g_Config.sD3D11Device.empty() && g_Config.sD3D11Device == adapterDescription) {
281
// Double check if it's the same default adapter
282
if (adapterDescription != currentDefaultAdapterName) {
283
customAdapter = pAdapter;
284
}
285
}
286
}
287
deviceFactory->Release();
288
289
if (m_vAdapters.size() == 1) {
290
// Only one (default) adapter, clear the list to hide device option from settings
291
m_vAdapters.clear();
292
}
293
294
bool reCreateDevice = false;
295
if (customAdapter) {
296
reCreateDevice = true;
297
// Recreate device with custom adapter
298
CreateDeviceResources(customAdapter);
299
}
300
301
return reCreateDevice;
302
}
303
304
// These resources need to be recreated every time the window size is changed.
305
void DX::DeviceResources::CreateWindowSizeDependentResources()
306
{
307
// Window pointer was previously submited by `SetWindow` called from (App.cpp)
308
// we don't have to do that since we can easily get the current window
309
auto coreWindow = CoreWindow::GetForCurrentThread();
310
311
SetWindow(coreWindow);
312
313
// Clear the previous window size specific context.
314
ID3D11RenderTargetView* nullViews[] = {nullptr};
315
m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
316
m_d3dRenderTargetView = nullptr;
317
m_d2dContext->SetTarget(nullptr);
318
m_d2dTargetBitmap = nullptr;
319
m_d3dContext->Flush1(D3D11_CONTEXT_TYPE_ALL, nullptr);
320
321
UpdateRenderTargetSize();
322
323
// The width and height of the swap chain must be based on the window's
324
// natively-oriented width and height. If the window is not in the native
325
// orientation, the dimensions must be reversed.
326
DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation();
327
328
bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270;
329
m_d3dRenderTargetSize.Width = swapDimensions ? m_outputSize.Height : m_outputSize.Width;
330
m_d3dRenderTargetSize.Height = swapDimensions ? m_outputSize.Width : m_outputSize.Height;
331
332
if (m_swapChain != nullptr)
333
{
334
// If the swap chain already exists, resize it.
335
HRESULT hr = m_swapChain->ResizeBuffers(
336
2, // Double-buffered swap chain.
337
lround(m_d3dRenderTargetSize.Width),
338
lround(m_d3dRenderTargetSize.Height),
339
DXGI_FORMAT_B8G8R8A8_UNORM,
340
0
341
);
342
343
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
344
{
345
// If the device was removed for any reason, a new device and swap chain will need to be created.
346
HandleDeviceLost();
347
348
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
349
// and correctly set up the new device.
350
return;
351
}
352
else
353
{
354
DX::ThrowIfFailed(hr);
355
}
356
}
357
else
358
{
359
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
360
DXGI_SCALING scaling = DisplayMetrics::SupportHighResolutions ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
361
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
362
363
swapChainDesc.Width = lround(m_d3dRenderTargetSize.Width); // Match the size of the window.
364
swapChainDesc.Height = lround(m_d3dRenderTargetSize.Height);
365
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
366
swapChainDesc.Stereo = false;
367
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
368
swapChainDesc.SampleDesc.Quality = 0;
369
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
370
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
371
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
372
swapChainDesc.Flags = 0;
373
swapChainDesc.Scaling = scaling;
374
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
375
376
ComPtr<IDXGISwapChain1> swapChain;
377
DX::ThrowIfFailed(
378
m_dxgiFactory->CreateSwapChainForCoreWindow(
379
m_d3dDevice.Get(),
380
reinterpret_cast<IUnknown*>(coreWindow),
381
&swapChainDesc,
382
nullptr,
383
&swapChain
384
)
385
);
386
DX::ThrowIfFailed(
387
swapChain.As(&m_swapChain)
388
);
389
390
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
391
// ensures that the application will only render after each VSync, minimizing power consumption.
392
DX::ThrowIfFailed(
393
m_dxgiDevice->SetMaximumFrameLatency(1)
394
);
395
}
396
397
// Set the proper orientation for the swap chain, and generate 2D and
398
// 3D matrix transformations for rendering to the rotated swap chain.
399
// Note the rotation angle for the 2D and 3D transforms are different.
400
// This is due to the difference in coordinate spaces. Additionally,
401
// the 3D matrix is specified explicitly to avoid rounding errors.
402
403
switch (displayRotation)
404
{
405
case DXGI_MODE_ROTATION_IDENTITY:
406
m_orientationTransform2D = Matrix3x2F::Identity();
407
m_orientationTransform3D = ScreenRotation::Rotation0;
408
break;
409
410
case DXGI_MODE_ROTATION_ROTATE90:
411
m_orientationTransform2D =
412
Matrix3x2F::Rotation(90.0f) *
413
Matrix3x2F::Translation(m_logicalSize.Height, 0.0f);
414
m_orientationTransform3D = ScreenRotation::Rotation270;
415
break;
416
417
case DXGI_MODE_ROTATION_ROTATE180:
418
m_orientationTransform2D =
419
Matrix3x2F::Rotation(180.0f) *
420
Matrix3x2F::Translation(m_logicalSize.Width, m_logicalSize.Height);
421
m_orientationTransform3D = ScreenRotation::Rotation180;
422
break;
423
424
case DXGI_MODE_ROTATION_ROTATE270:
425
m_orientationTransform2D =
426
Matrix3x2F::Rotation(270.0f) *
427
Matrix3x2F::Translation(0.0f, m_logicalSize.Width);
428
m_orientationTransform3D = ScreenRotation::Rotation90;
429
break;
430
431
default:
432
throw ref new FailureException();
433
}
434
435
DX::ThrowIfFailed(
436
m_swapChain->SetRotation(displayRotation)
437
);
438
439
// Create a render target view of the swap chain back buffer.
440
ComPtr<ID3D11Texture2D1> backBuffer;
441
DX::ThrowIfFailed(
442
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
443
);
444
445
DX::ThrowIfFailed(
446
m_d3dDevice->CreateRenderTargetView1(
447
backBuffer.Get(),
448
nullptr,
449
&m_d3dRenderTargetView
450
)
451
);
452
453
// Set the 3D rendering viewport to target the entire window.
454
m_screenViewport = CD3D11_VIEWPORT(
455
0.0f,
456
0.0f,
457
m_d3dRenderTargetSize.Width,
458
m_d3dRenderTargetSize.Height
459
);
460
461
m_d3dContext->RSSetViewports(1, &m_screenViewport);
462
463
// Create a Direct2D target bitmap associated with the
464
// swap chain back buffer and set it as the current target.
465
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
466
D2D1::BitmapProperties1(
467
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
468
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
469
m_dpi,
470
m_dpi
471
);
472
473
ComPtr<IDXGISurface2> dxgiBackBuffer;
474
DX::ThrowIfFailed(
475
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
476
);
477
478
DX::ThrowIfFailed(
479
m_d2dContext->CreateBitmapFromDxgiSurface(
480
dxgiBackBuffer.Get(),
481
&bitmapProperties,
482
&m_d2dTargetBitmap
483
)
484
);
485
486
m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
487
m_d2dContext->SetDpi(m_effectiveDpi, m_effectiveDpi);
488
489
// Grayscale text anti-aliasing is recommended for all Windows Store apps.
490
m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
491
}
492
493
// Determine the dimensions of the render target and whether it will be scaled down.
494
void DX::DeviceResources::UpdateRenderTargetSize()
495
{
496
m_effectiveDpi = m_dpi;
497
if (Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamily == L"Windows.Xbox")
498
{
499
m_effectiveDpi = 96.0f / static_cast<float>(m_logicalSize.Height) * 1080.0f;
500
}
501
else
502
{
503
// To improve battery life on high resolution devices, render to a smaller render target
504
// and allow the GPU to scale the output when it is presented.
505
if (!DisplayMetrics::SupportHighResolutions && m_dpi >= DisplayMetrics::DpiThreshold)
506
{
507
float width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_dpi);
508
float height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_dpi);
509
510
// When the device is in portrait orientation, height > width. Compare the
511
// larger dimension against the width threshold and the smaller dimension
512
// against the height threshold.
513
if (std::max(width, height) > DisplayMetrics::WidthThreshold && std::min(width, height) > DisplayMetrics::HeightThreshold)
514
{
515
// To scale the app we change the effective DPI. Logical size does not change.
516
m_effectiveDpi /= 2.0f;
517
}
518
}
519
}
520
// Calculate the necessary render target size in pixels.
521
m_outputSize.Width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_effectiveDpi);
522
m_outputSize.Height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_effectiveDpi);
523
524
// Prevent zero size DirectX content from being created.
525
m_outputSize.Width = std::max(m_outputSize.Width, 1.0f);
526
m_outputSize.Height = std::max(m_outputSize.Height, 1.0f);
527
}
528
529
// This method is called when the CoreWindow is created (or re-created).
530
void DX::DeviceResources::SetWindow(CoreWindow^ window)
531
{
532
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
533
534
if (Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamily == L"Windows.Xbox")
535
{
536
const auto hdi = Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView();
537
if (hdi)
538
{
539
try
540
{
541
const auto dm = hdi->GetCurrentDisplayMode();
542
const float hdmi_width = (float)dm->ResolutionWidthInRawPixels;
543
const float hdmi_height = (float)dm->ResolutionHeightInRawPixels;
544
// If we're running on Xbox, use the HDMI mode instead of the CoreWindow size.
545
// In UWP, the CoreWindow is always 1920x1080, even when running at 4K.
546
547
m_logicalSize = Windows::Foundation::Size(hdmi_width, hdmi_height);
548
m_dpi = currentDisplayInformation->LogicalDpi * 1.5f;
549
}
550
catch (const Platform::Exception^)
551
{
552
m_logicalSize = Windows::Foundation::Size(window->Bounds.Width, window->Bounds.Height);
553
m_dpi = currentDisplayInformation->LogicalDpi;
554
}
555
}
556
}
557
else
558
{
559
m_logicalSize = Windows::Foundation::Size(window->Bounds.Width, window->Bounds.Height);
560
m_dpi = currentDisplayInformation->LogicalDpi;
561
}
562
m_nativeOrientation = currentDisplayInformation->NativeOrientation;
563
m_currentOrientation = currentDisplayInformation->CurrentOrientation;
564
565
m_d2dContext->SetDpi(m_dpi, m_dpi);
566
}
567
568
// This method is called in the event handler for the SizeChanged event.
569
void DX::DeviceResources::SetLogicalSize(Windows::Foundation::Size logicalSize)
570
{
571
if (m_logicalSize != logicalSize)
572
{
573
m_logicalSize = logicalSize;
574
CreateWindowSizeDependentResources();
575
}
576
}
577
578
// This method is called in the event handler for the DpiChanged event.
579
void DX::DeviceResources::SetDpi(float dpi)
580
{
581
if (dpi != m_dpi)
582
{
583
m_dpi = dpi;
584
585
// When the display DPI changes, the logical size of the window (measured in Dips)
586
// also changes and needs to be updated.
587
CreateWindowSizeDependentResources();
588
}
589
}
590
591
// This method is called in the event handler for the OrientationChanged event.
592
void DX::DeviceResources::SetCurrentOrientation(DisplayOrientations currentOrientation)
593
{
594
if (m_currentOrientation != currentOrientation)
595
{
596
m_currentOrientation = currentOrientation;
597
CreateWindowSizeDependentResources();
598
}
599
}
600
601
// This method is called in the event handler for the DisplayContentsInvalidated event.
602
void DX::DeviceResources::ValidateDevice()
603
{
604
// The D3D Device is no longer valid if the default adapter changed since the device
605
// was created or if the device has been removed.
606
607
// First, get the information for the default adapter from when the device was created.
608
ComPtr<IDXGIAdapter1> previousDefaultAdapter;
609
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &previousDefaultAdapter));
610
611
DXGI_ADAPTER_DESC1 previousDesc;
612
DX::ThrowIfFailed(previousDefaultAdapter->GetDesc1(&previousDesc));
613
614
// Next, get the information for the current default adapter.
615
616
ComPtr<IDXGIFactory4> currentFactory;
617
DX::ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&currentFactory)));
618
619
ComPtr<IDXGIAdapter1> currentDefaultAdapter;
620
DX::ThrowIfFailed(currentFactory->EnumAdapters1(0, &currentDefaultAdapter));
621
622
DXGI_ADAPTER_DESC1 currentDesc;
623
DX::ThrowIfFailed(currentDefaultAdapter->GetDesc1(&currentDesc));
624
625
// If the adapter LUIDs don't match, or if the device reports that it has been removed,
626
// a new D3D device must be created.
627
628
if (previousDesc.AdapterLuid.LowPart != currentDesc.AdapterLuid.LowPart ||
629
previousDesc.AdapterLuid.HighPart != currentDesc.AdapterLuid.HighPart ||
630
FAILED(m_d3dDevice->GetDeviceRemovedReason()))
631
{
632
// Release references to resources related to the old device.
633
previousDefaultAdapter = nullptr;
634
635
// Create a new device and swap chain.
636
HandleDeviceLost();
637
}
638
}
639
640
// Recreate all device resources and set them back to the current state.
641
void DX::DeviceResources::HandleDeviceLost()
642
{
643
m_swapChain = nullptr;
644
645
if (m_deviceNotify != nullptr)
646
{
647
m_deviceNotify->OnDeviceLost();
648
}
649
650
CreateDeviceResources();
651
m_d2dContext->SetDpi(m_dpi, m_dpi);
652
CreateWindowSizeDependentResources();
653
654
if (m_deviceNotify != nullptr)
655
{
656
m_deviceNotify->OnDeviceRestored();
657
}
658
}
659
660
// Register our DeviceNotify to be informed on device lost and creation.
661
void DX::DeviceResources::RegisterDeviceNotify(DX::IDeviceNotify* deviceNotify)
662
{
663
m_deviceNotify = deviceNotify;
664
}
665
666
// Call this method when the app suspends. It provides a hint to the driver that the app
667
// is entering an idle state and that temporary buffers can be reclaimed for use by other apps.
668
void DX::DeviceResources::Trim()
669
{
670
ComPtr<IDXGIDevice3> dxgiDevice;
671
m_d3dDevice.As(&dxgiDevice);
672
673
dxgiDevice->Trim();
674
}
675
676
// Present the contents of the swap chain to the screen.
677
void DX::DeviceResources::Present()
678
{
679
// The first argument instructs DXGI to block until VSync, putting the application
680
// to sleep until the next VSync. This ensures we don't waste any cycles rendering
681
// frames that will never be displayed to the screen.
682
DXGI_PRESENT_PARAMETERS parameters = { 0 };
683
HRESULT hr = m_swapChain->Present1(1, 0, &parameters);
684
685
// Discard the contents of the render target.
686
// This is a valid operation only when the existing contents will be entirely
687
// overwritten. If dirty or scroll rects are used, this call should be removed.
688
m_d3dContext->DiscardView1(m_d3dRenderTargetView.Get(), nullptr, 0);
689
690
// If the device was removed either by a disconnection or a driver upgrade, we
691
// must recreate all device resources.
692
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
693
{
694
HandleDeviceLost();
695
}
696
else
697
{
698
DX::ThrowIfFailed(hr);
699
}
700
}
701
702
// This method determines the rotation between the display device's native orientation and the
703
// current display orientation.
704
DXGI_MODE_ROTATION DX::DeviceResources::ComputeDisplayRotation()
705
{
706
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
707
708
// Note: NativeOrientation can only be Landscape or Portrait even though
709
// the DisplayOrientations enum has other values.
710
switch (m_nativeOrientation)
711
{
712
case DisplayOrientations::Landscape:
713
switch (m_currentOrientation)
714
{
715
case DisplayOrientations::Landscape:
716
rotation = DXGI_MODE_ROTATION_IDENTITY;
717
break;
718
719
case DisplayOrientations::Portrait:
720
rotation = DXGI_MODE_ROTATION_ROTATE270;
721
break;
722
723
case DisplayOrientations::LandscapeFlipped:
724
rotation = DXGI_MODE_ROTATION_ROTATE180;
725
break;
726
727
case DisplayOrientations::PortraitFlipped:
728
rotation = DXGI_MODE_ROTATION_ROTATE90;
729
break;
730
}
731
break;
732
733
case DisplayOrientations::Portrait:
734
switch (m_currentOrientation)
735
{
736
case DisplayOrientations::Landscape:
737
rotation = DXGI_MODE_ROTATION_ROTATE90;
738
break;
739
740
case DisplayOrientations::Portrait:
741
rotation = DXGI_MODE_ROTATION_IDENTITY;
742
break;
743
744
case DisplayOrientations::LandscapeFlipped:
745
rotation = DXGI_MODE_ROTATION_ROTATE270;
746
break;
747
748
case DisplayOrientations::PortraitFlipped:
749
rotation = DXGI_MODE_ROTATION_ROTATE180;
750
break;
751
}
752
break;
753
}
754
return rotation;
755
}
756
757