-
Notifications
You must be signed in to change notification settings - Fork 226
/
DeviceResources.cpp
251 lines (217 loc) · 8.41 KB
/
DeviceResources.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//
// DeviceResources.cpp - A wrapper for the Direct3D 11 device and swapchain
// (requires DirectX 11.X Xbox One Monolithic Runtime)
//
#include "pch.h"
#include "DeviceResources.h"
using namespace DirectX;
using namespace DX;
using Microsoft::WRL::ComPtr;
// Constructor for DeviceResources.
DeviceResources::DeviceResources(DXGI_FORMAT backBufferFormat, DXGI_FORMAT depthBufferFormat, UINT backBufferCount, unsigned int flags) :
m_screenViewport{},
m_backBufferFormat(backBufferFormat),
m_depthBufferFormat(depthBufferFormat),
m_backBufferCount(backBufferCount),
m_window(nullptr),
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_1),
m_outputSize{0, 0, 1920, 1080},
m_options(flags)
{
}
// Configures the Direct3D device, and stores handles to it and the device context.
void DeviceResources::CreateDeviceResources()
{
D3D11X_CREATE_DEVICE_PARAMETERS params = {};
params.Version = D3D11_SDK_VERSION;
#ifdef _DEBUG
// Enable the debug layer.
params.Flags = D3D11_CREATE_DEVICE_DEBUG;
#elif defined(PROFILE)
// Enable the instrumented driver.
params.Flags = D3D11_CREATE_DEVICE_INSTRUMENTED;
#endif
if (m_options & c_FastSemantics)
{
params.Flags |= D3D11_CREATE_DEVICE_IMMEDIATE_CONTEXT_FAST_SEMANTICS;
}
// Create the Direct3D 11 API device object and a corresponding context.
ThrowIfFailed(D3D11XCreateDeviceX(
¶ms,
m_d3dDevice.ReleaseAndGetAddressOf(),
m_d3dContext.ReleaseAndGetAddressOf()
));
#ifndef NDEBUG
ComPtr<ID3D11InfoQueue> d3dInfoQueue;
if (SUCCEEDED(m_d3dDevice.As(&d3dInfoQueue)))
{
#ifdef _DEBUG
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
#endif
D3D11_MESSAGE_ID hide[] =
{
D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
};
D3D11_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = _countof(hide);
filter.DenyList.pIDList = hide;
d3dInfoQueue->AddStorageFilterEntries(&filter);
}
#endif
if (m_options & c_Enable4K_UHD)
{
#if _XDK_VER >= 0x3F6803F3 /* XDK Edition 170600 */
D3D11X_GPU_HARDWARE_CONFIGURATION hwConfig = {};
m_d3dDevice->GetGpuHardwareConfiguration(&hwConfig);
if (hwConfig.HardwareVersion >= D3D11X_HARDWARE_VERSION_XBOX_ONE_X)
{
m_outputSize = { 0, 0, 3840, 2160 };
#ifdef _DEBUG
OutputDebugStringA("INFO: Swapchain using 4k (3840 x 2160) on Xbox One X\n");
#endif
}
else
{
m_options &= ~c_Enable4K_UHD;
#ifdef _DEBUG
OutputDebugStringA("INFO: Swapchain using 1080p (1920 x 1080) on Xbox One or Xbox One S\n");
#endif
}
#else
m_options &= ~c_Enable4K_UHD;
#ifdef _DEBUG
OutputDebugStringA("WARNING: Hardware detection not supported on this XDK edition; Swapchain using 1080p (1920 x 1080)\n");
#endif
#endif
}
}
// These resources need to be recreated every time the window size is changed.
void DeviceResources::CreateWindowSizeDependentResources()
{
if (!m_window)
{
throw std::exception("Call SetWindow with a valid CoreWindow pointer");
}
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews[] = {nullptr};
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
m_d3dRenderTargetView.Reset();
m_d3dDepthStencilView.Reset();
m_renderTarget.Reset();
m_depthStencil.Reset();
m_d3dContext->Flush();
// Determine the render target size in pixels.
UINT backBufferWidth = std::max<UINT>(m_outputSize.right - m_outputSize.left, 1);
UINT backBufferHeight = std::max<UINT>(m_outputSize.bottom - m_outputSize.top, 1);
if (m_swapChain)
{
// If the swap chain already exists, resize it.
ThrowIfFailed(m_swapChain->ResizeBuffers(
m_backBufferCount,
backBufferWidth,
backBufferHeight,
m_backBufferFormat,
0
));
// Xbox One apps do not need to handle DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET.
}
else
{
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
// This sequence obtains the DXGI factory that was used to create the Direct3D device above.
ComPtr<IDXGIDevice1> dxgiDevice;
ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
ComPtr<IDXGIAdapter> dxgiAdapter;
ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));
ComPtr<IDXGIFactory2> dxgiFactory;
ThrowIfFailed(dxgiAdapter->GetParent(IID_GRAPHICS_PPV_ARGS(dxgiFactory.GetAddressOf())));
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = backBufferWidth;
swapChainDesc.Height = backBufferHeight;
swapChainDesc.Format = m_backBufferFormat;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = m_backBufferCount;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swapChainDesc.Flags = DXGIX_SWAP_CHAIN_FLAG_QUANTIZATION_RGB_FULL;
// Create a SwapChain from a CoreWindow.
ThrowIfFailed(dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
m_window,
&swapChainDesc,
nullptr,
m_swapChain.GetAddressOf()
));
}
// Create a render target view of the swap chain back buffer.
ThrowIfFailed(m_swapChain->GetBuffer(0, IID_GRAPHICS_PPV_ARGS(m_renderTarget.ReleaseAndGetAddressOf())));
m_renderTarget->SetName(L"Render target");
ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(
m_renderTarget.Get(),
nullptr,
m_d3dRenderTargetView.ReleaseAndGetAddressOf()
));
if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)
{
// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
m_depthBufferFormat,
backBufferWidth,
backBufferHeight,
1, // This depth stencil view has only one texture.
1, // Use a single mipmap level.
D3D11_BIND_DEPTH_STENCIL
);
ThrowIfFailed(m_d3dDevice->CreateTexture2D(
&depthStencilDesc,
nullptr,
m_depthStencil.ReleaseAndGetAddressOf()
));
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
ThrowIfFailed(m_d3dDevice->CreateDepthStencilView(
m_depthStencil.Get(),
&depthStencilViewDesc,
m_d3dDepthStencilView.ReleaseAndGetAddressOf()
));
}
// Set the 3D rendering viewport to target the entire window.
m_screenViewport = CD3D11_VIEWPORT(
0.0f,
0.0f,
static_cast<float>(backBufferWidth),
static_cast<float>(backBufferHeight)
);
m_outputSize.left = m_outputSize.top = 0;
m_outputSize.right = backBufferWidth;
m_outputSize.bottom = backBufferHeight;
}
// Prepare the render target for rendering.
void DeviceResources::Prepare()
{
if (m_options & c_FastSemantics)
{
ThrowIfFailed(m_swapChain->GetBuffer(0, IID_GRAPHICS_PPV_ARGS(m_renderTarget.ReleaseAndGetAddressOf())));
m_d3dDevice->PlaceSwapChainView(m_renderTarget.Get(), m_d3dRenderTargetView.Get());
m_d3dContext->InsertWaitOnPresent(0, m_renderTarget.Get());
}
}
// Present the contents of the swap chain to the screen.
void DeviceResources::Present(UINT decompressFlags)
{
if ((m_options & c_FastSemantics) != 0 && decompressFlags != 0)
{
m_d3dContext->DecompressResource(
m_renderTarget.Get(), 0, nullptr,
m_renderTarget.Get(), 0, nullptr,
m_backBufferFormat, decompressFlags);
}
// The first argument instructs DXGI to block until VSync, putting the application
// to sleep until the next VSync. This ensures we don't waste any cycles rendering
// frames that will never be displayed to the screen.
ThrowIfFailed(m_swapChain->Present(1, 0));
// Xbox One apps do not need to handle DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET.
}