1 | #include <d3dcompiler.h>
|
---|
2 | #include <d3d11_1.h>
|
---|
3 | #include <dxgi1_3.h>
|
---|
4 |
|
---|
5 | #include <windows.h>
|
---|
6 | #include <windowsx.h>
|
---|
7 |
|
---|
8 | #include <cstring>
|
---|
9 | #include <string>
|
---|
10 | #include <sstream>
|
---|
11 |
|
---|
12 | #include "../test_utils.h"
|
---|
13 |
|
---|
14 | using namespace dxvk;
|
---|
15 |
|
---|
16 | struct Vertex {
|
---|
17 | float x, y;
|
---|
18 | };
|
---|
19 |
|
---|
20 | struct VsConstants {
|
---|
21 | float x, y;
|
---|
22 | float w, h;
|
---|
23 | };
|
---|
24 |
|
---|
25 | struct VsConstantsPad {
|
---|
26 | VsConstants data;
|
---|
27 | uint32_t pad[60];
|
---|
28 | };
|
---|
29 |
|
---|
30 | struct PsConstants {
|
---|
31 | float r, g, b, a;
|
---|
32 | };
|
---|
33 |
|
---|
34 | struct DrawOptions {
|
---|
35 | bool mapDiscardOnce;
|
---|
36 | bool sortByTexture;
|
---|
37 | bool drawIndexed;
|
---|
38 | };
|
---|
39 |
|
---|
40 | const std::string g_vertexShaderCode =
|
---|
41 | "cbuffer vs_cb : register(b0) {\n"
|
---|
42 | " float2 v_offset;\n"
|
---|
43 | " float2 v_scale;\n"
|
---|
44 | "};\n"
|
---|
45 | "float4 main(float4 v_pos : IN_POSITION) : SV_POSITION {\n"
|
---|
46 | " float2 coord = 2.0f * (v_pos * v_scale + v_offset) - 1.0f;\n"
|
---|
47 | " return float4(coord, 0.0f, 1.0f);\n"
|
---|
48 | "}\n";
|
---|
49 |
|
---|
50 | const std::string g_pixelShaderCode =
|
---|
51 | "Texture2D<float4> tex0 : register(t0);"
|
---|
52 | "cbuffer ps_cb : register(b0) {\n"
|
---|
53 | " float4 color;\n"
|
---|
54 | "};\n"
|
---|
55 | "float4 main() : SV_TARGET {\n"
|
---|
56 | " return color * tex0.Load(int3(0, 0, 0));\n"
|
---|
57 | "}\n";
|
---|
58 |
|
---|
59 | class TriangleApp {
|
---|
60 |
|
---|
61 | public:
|
---|
62 |
|
---|
63 | TriangleApp(HINSTANCE instance, HWND window)
|
---|
64 | : m_window(window) {
|
---|
65 | Com<ID3D11Device> device;
|
---|
66 |
|
---|
67 | D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_1;
|
---|
68 |
|
---|
69 | HRESULT status = D3D11CreateDevice(
|
---|
70 | nullptr, D3D_DRIVER_TYPE_HARDWARE,
|
---|
71 | nullptr, 0, &fl, 1, D3D11_SDK_VERSION,
|
---|
72 | &device, nullptr, nullptr);
|
---|
73 |
|
---|
74 | if (FAILED(status)) {
|
---|
75 | std::cerr << "Failed to create D3D11 device" << std::endl;
|
---|
76 | return;
|
---|
77 | }
|
---|
78 |
|
---|
79 | if (FAILED(device->QueryInterface(IID_PPV_ARGS(&m_device)))) {
|
---|
80 | std::cerr << "Failed to query ID3D11DeviceContext1" << std::endl;
|
---|
81 | return;
|
---|
82 | }
|
---|
83 |
|
---|
84 | Com<IDXGIDevice> dxgiDevice;
|
---|
85 |
|
---|
86 | if (FAILED(m_device->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))) {
|
---|
87 | std::cerr << "Failed to query DXGI device" << std::endl;
|
---|
88 | return;
|
---|
89 | }
|
---|
90 |
|
---|
91 | if (FAILED(dxgiDevice->GetAdapter(&m_adapter))) {
|
---|
92 | std::cerr << "Failed to query DXGI adapter" << std::endl;
|
---|
93 | return;
|
---|
94 | }
|
---|
95 |
|
---|
96 | if (FAILED(m_adapter->GetParent(IID_PPV_ARGS(&m_factory)))) {
|
---|
97 | std::cerr << "Failed to query DXGI factory" << std::endl;
|
---|
98 | return;
|
---|
99 | }
|
---|
100 |
|
---|
101 | m_device->GetImmediateContext1(&m_context);
|
---|
102 |
|
---|
103 | DXGI_SWAP_CHAIN_DESC1 swapDesc;
|
---|
104 | swapDesc.Width = m_windowSizeW;
|
---|
105 | swapDesc.Height = m_windowSizeH;
|
---|
106 | swapDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
---|
107 | swapDesc.Stereo = FALSE;
|
---|
108 | swapDesc.SampleDesc = { 1, 0 };
|
---|
109 | swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
---|
110 | swapDesc.BufferCount = 3;
|
---|
111 | swapDesc.Scaling = DXGI_SCALING_STRETCH;
|
---|
112 | swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
---|
113 | swapDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
---|
114 | swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
|
---|
115 | | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
---|
116 |
|
---|
117 | DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsDesc;
|
---|
118 | fsDesc.RefreshRate = { 0, 0 };
|
---|
119 | fsDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
---|
120 | fsDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
---|
121 | fsDesc.Windowed = TRUE;
|
---|
122 |
|
---|
123 | Com<IDXGISwapChain1> swapChain;
|
---|
124 | if (FAILED(m_factory->CreateSwapChainForHwnd(m_device.ptr(), m_window, &swapDesc, &fsDesc, nullptr, &swapChain))) {
|
---|
125 | std::cerr << "Failed to create DXGI swap chain" << std::endl;
|
---|
126 | return;
|
---|
127 | }
|
---|
128 |
|
---|
129 | if (FAILED(swapChain->QueryInterface(IID_PPV_ARGS(&m_swapChain)))) {
|
---|
130 | std::cerr << "Failed to query DXGI swap chain interface" << std::endl;
|
---|
131 | return;
|
---|
132 | }
|
---|
133 |
|
---|
134 | m_factory->MakeWindowAssociation(m_window, 0);
|
---|
135 |
|
---|
136 | Com<ID3DBlob> vertexShaderBlob;
|
---|
137 | Com<ID3DBlob> pixelShaderBlob;
|
---|
138 |
|
---|
139 | if (FAILED(D3DCompile(g_vertexShaderCode.data(), g_vertexShaderCode.size(),
|
---|
140 | "Vertex shader", nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr))) {
|
---|
141 | std::cerr << "Failed to compile vertex shader" << std::endl;
|
---|
142 | return;
|
---|
143 | }
|
---|
144 |
|
---|
145 | if (FAILED(D3DCompile(g_pixelShaderCode.data(), g_pixelShaderCode.size(),
|
---|
146 | "Pixel shader", nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr))) {
|
---|
147 | std::cerr << "Failed to compile pixel shader" << std::endl;
|
---|
148 | return;
|
---|
149 | }
|
---|
150 |
|
---|
151 | if (FAILED(m_device->CreateVertexShader(
|
---|
152 | vertexShaderBlob->GetBufferPointer(),
|
---|
153 | vertexShaderBlob->GetBufferSize(),
|
---|
154 | nullptr, &m_vs))) {
|
---|
155 | std::cerr << "Failed to create vertex shader" << std::endl;
|
---|
156 | return;
|
---|
157 | }
|
---|
158 |
|
---|
159 | if (FAILED(m_device->CreatePixelShader(
|
---|
160 | pixelShaderBlob->GetBufferPointer(),
|
---|
161 | pixelShaderBlob->GetBufferSize(),
|
---|
162 | nullptr, &m_ps))) {
|
---|
163 | std::cerr << "Failed to create pixel shader" << std::endl;
|
---|
164 | return;
|
---|
165 | }
|
---|
166 |
|
---|
167 | std::array<D3D11_INPUT_ELEMENT_DESC, 1> vertexFormatDesc = {{
|
---|
168 | { "IN_POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
---|
169 | }};
|
---|
170 |
|
---|
171 | if (FAILED(m_device->CreateInputLayout(
|
---|
172 | vertexFormatDesc.data(),
|
---|
173 | vertexFormatDesc.size(),
|
---|
174 | vertexShaderBlob->GetBufferPointer(),
|
---|
175 | vertexShaderBlob->GetBufferSize(),
|
---|
176 | &m_vertexFormat))) {
|
---|
177 | std::cerr << "Failed to create input layout" << std::endl;
|
---|
178 | return;
|
---|
179 | }
|
---|
180 |
|
---|
181 | std::array<Vertex, 6> vertexData = {{
|
---|
182 | Vertex { -0.3f, 0.1f },
|
---|
183 | Vertex { 0.5f, 0.9f },
|
---|
184 | Vertex { 1.3f, 0.1f },
|
---|
185 | Vertex { -0.3f, 0.9f },
|
---|
186 | Vertex { 1.3f, 0.9f },
|
---|
187 | Vertex { 0.5f, 0.1f },
|
---|
188 | }};
|
---|
189 |
|
---|
190 | D3D11_BUFFER_DESC vboDesc;
|
---|
191 | vboDesc.ByteWidth = sizeof(vertexData);
|
---|
192 | vboDesc.Usage = D3D11_USAGE_IMMUTABLE;
|
---|
193 | vboDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
---|
194 | vboDesc.CPUAccessFlags = 0;
|
---|
195 | vboDesc.MiscFlags = 0;
|
---|
196 | vboDesc.StructureByteStride = 0;
|
---|
197 |
|
---|
198 | D3D11_SUBRESOURCE_DATA vboData;
|
---|
199 | vboData.pSysMem = vertexData.data();
|
---|
200 | vboData.SysMemPitch = vboDesc.ByteWidth;
|
---|
201 | vboData.SysMemSlicePitch = vboDesc.ByteWidth;
|
---|
202 |
|
---|
203 | if (FAILED(m_device->CreateBuffer(&vboDesc, &vboData, &m_vbo))) {
|
---|
204 | std::cerr << "Failed to create index buffer" << std::endl;
|
---|
205 | return;
|
---|
206 | }
|
---|
207 |
|
---|
208 | std::array<uint32_t, 6> indexData = {{ 0, 1, 2, 3, 4, 5 }};
|
---|
209 |
|
---|
210 | D3D11_BUFFER_DESC iboDesc;
|
---|
211 | iboDesc.ByteWidth = sizeof(indexData);
|
---|
212 | iboDesc.Usage = D3D11_USAGE_IMMUTABLE;
|
---|
213 | iboDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
---|
214 | iboDesc.CPUAccessFlags = 0;
|
---|
215 | iboDesc.MiscFlags = 0;
|
---|
216 | iboDesc.StructureByteStride = 0;
|
---|
217 |
|
---|
218 | D3D11_SUBRESOURCE_DATA iboData;
|
---|
219 | iboData.pSysMem = indexData.data();
|
---|
220 | iboData.SysMemPitch = iboDesc.ByteWidth;
|
---|
221 | iboData.SysMemSlicePitch = iboDesc.ByteWidth;
|
---|
222 |
|
---|
223 | if (FAILED(m_device->CreateBuffer(&iboDesc, &iboData, &m_ibo))) {
|
---|
224 | std::cerr << "Failed to create index buffer" << std::endl;
|
---|
225 | return;
|
---|
226 | }
|
---|
227 |
|
---|
228 | D3D11_BUFFER_DESC cbDesc;
|
---|
229 | cbDesc.ByteWidth = sizeof(PsConstants);
|
---|
230 | cbDesc.Usage = D3D11_USAGE_DYNAMIC;
|
---|
231 | cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
---|
232 | cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
---|
233 | cbDesc.MiscFlags = 0;
|
---|
234 | cbDesc.StructureByteStride = 0;
|
---|
235 |
|
---|
236 | if (FAILED(m_device->CreateBuffer(&cbDesc, nullptr, &m_cbPs))) {
|
---|
237 | std::cerr << "Failed to create constant buffer" << std::endl;
|
---|
238 | return;
|
---|
239 | }
|
---|
240 |
|
---|
241 | cbDesc.ByteWidth = sizeof(VsConstantsPad) * 128 * 8;
|
---|
242 |
|
---|
243 | if (FAILED(m_device->CreateBuffer(&cbDesc, nullptr, &m_cbVs))) {
|
---|
244 | std::cerr << "Failed to create constant buffer" << std::endl;
|
---|
245 | return;
|
---|
246 | }
|
---|
247 |
|
---|
248 | std::array<uint32_t, 2> colors = { 0xFFFFFFFF, 0xFFC0C0C0 };
|
---|
249 |
|
---|
250 | D3D11_SUBRESOURCE_DATA texData;
|
---|
251 | texData.pSysMem = &colors[0];
|
---|
252 | texData.SysMemPitch = sizeof(colors[0]);
|
---|
253 | texData.SysMemSlicePitch = sizeof(colors[0]);
|
---|
254 |
|
---|
255 | D3D11_TEXTURE2D_DESC texDesc;
|
---|
256 | texDesc.Width = 1;
|
---|
257 | texDesc.Height = 1;
|
---|
258 | texDesc.MipLevels = 1;
|
---|
259 | texDesc.ArraySize = 1;
|
---|
260 | texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
---|
261 | texDesc.SampleDesc = { 1, 0 };
|
---|
262 | texDesc.Usage = D3D11_USAGE_IMMUTABLE;
|
---|
263 | texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
---|
264 | texDesc.CPUAccessFlags = 0;
|
---|
265 | texDesc.MiscFlags = 0;
|
---|
266 |
|
---|
267 | if (FAILED(m_device->CreateTexture2D(&texDesc, &texData, &m_tex0))) {
|
---|
268 | std::cerr << "Failed to create texture" << std::endl;
|
---|
269 | return;
|
---|
270 | }
|
---|
271 |
|
---|
272 | texData.pSysMem = &colors[1];
|
---|
273 |
|
---|
274 | if (FAILED(m_device->CreateTexture2D(&texDesc, &texData, &m_tex1))) {
|
---|
275 | std::cerr << "Failed to create texture" << std::endl;
|
---|
276 | return;
|
---|
277 | }
|
---|
278 |
|
---|
279 | if (FAILED(m_device->CreateShaderResourceView(m_tex0.ptr(), nullptr, &m_srv0))
|
---|
280 | || FAILED(m_device->CreateShaderResourceView(m_tex1.ptr(), nullptr, &m_srv1))) {
|
---|
281 | std::cerr << "Failed to create SRV" << std::endl;
|
---|
282 | return;
|
---|
283 | }
|
---|
284 |
|
---|
285 | m_initialized = true;
|
---|
286 | }
|
---|
287 |
|
---|
288 |
|
---|
289 | ~TriangleApp() {
|
---|
290 | m_context->ClearState();
|
---|
291 | }
|
---|
292 |
|
---|
293 |
|
---|
294 | bool run() {
|
---|
295 | if (!m_initialized)
|
---|
296 | return false;
|
---|
297 |
|
---|
298 | if (m_occluded && (m_occluded = isOccluded()))
|
---|
299 | return true;
|
---|
300 |
|
---|
301 | if (!beginFrame())
|
---|
302 | return true;
|
---|
303 |
|
---|
304 | std::array<PsConstants, 2> colors = {{
|
---|
305 | PsConstants { 0.25f, 0.25f, 0.25f, 1.0f },
|
---|
306 | PsConstants { 0.40f, 0.40f, 0.40f, 1.0f },
|
---|
307 | }};
|
---|
308 |
|
---|
309 | for (uint32_t i = 0; i < 8; i++) {
|
---|
310 | DrawOptions options;
|
---|
311 | options.sortByTexture = i & 1;
|
---|
312 | options.drawIndexed = i & 2;
|
---|
313 | options.mapDiscardOnce = i & 4;
|
---|
314 | drawLines(colors[i & 1], options, i);
|
---|
315 | }
|
---|
316 |
|
---|
317 | if (!endFrame())
|
---|
318 | return false;
|
---|
319 |
|
---|
320 | updateFps();
|
---|
321 | return true;
|
---|
322 | }
|
---|
323 |
|
---|
324 |
|
---|
325 | void drawLines(const PsConstants& psData, const DrawOptions& options, uint32_t baseY) {
|
---|
326 | D3D11_MAPPED_SUBRESOURCE sr;
|
---|
327 |
|
---|
328 | // Update color for the row
|
---|
329 | m_context->PSSetConstantBuffers(0, 1, &m_cbPs);
|
---|
330 | m_context->Map(m_cbPs.ptr(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
|
---|
331 | std::memcpy(sr.pData, &psData, sizeof(psData));
|
---|
332 | m_context->Unmap(m_cbPs.ptr(), 0);
|
---|
333 |
|
---|
334 | baseY *= 8;
|
---|
335 |
|
---|
336 | if (options.mapDiscardOnce) {
|
---|
337 | uint32_t drawIndex = 0;
|
---|
338 |
|
---|
339 | // Discard and map the entire vertex constant buffer
|
---|
340 | // once, then bind sub-ranges while emitting draw calls
|
---|
341 | m_context->Map(m_cbVs.ptr(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
|
---|
342 | auto vsData = reinterpret_cast<VsConstantsPad*>(sr.pData);
|
---|
343 |
|
---|
344 | for (uint32_t y = 0; y < 8; y++) {
|
---|
345 | for (uint32_t x = 0; x < 128; x++)
|
---|
346 | vsData[drawIndex++].data = getVsConstants(x, baseY + y);
|
---|
347 | }
|
---|
348 |
|
---|
349 | m_context->Unmap(m_cbVs.ptr(), 0);
|
---|
350 | }
|
---|
351 |
|
---|
352 | if (options.drawIndexed)
|
---|
353 | m_context->IASetIndexBuffer(m_ibo.ptr(), DXGI_FORMAT_R32_UINT, 0);
|
---|
354 |
|
---|
355 | uint32_t vsStride = sizeof(Vertex);
|
---|
356 | uint32_t vsOffset = 0;
|
---|
357 | m_context->IASetVertexBuffers(0, 1, &m_vbo, &vsStride, &vsOffset);
|
---|
358 |
|
---|
359 | uint32_t maxZ = options.sortByTexture ? 2 : 1;
|
---|
360 |
|
---|
361 | for (uint32_t z = 0; z < maxZ; z++) {
|
---|
362 | uint32_t drawIndex = z;
|
---|
363 |
|
---|
364 | if (options.sortByTexture) {
|
---|
365 | ID3D11ShaderResourceView* view = z ? m_srv1.ptr() : m_srv0.ptr();
|
---|
366 | m_context->PSSetShaderResources(0, 1, &view);
|
---|
367 | }
|
---|
368 |
|
---|
369 | for (uint32_t y = 0; y < 8; y++) {
|
---|
370 | for (uint32_t x = z; x < 128; x += maxZ) {
|
---|
371 | uint32_t triIndex = (x ^ y) & 1;
|
---|
372 |
|
---|
373 | if (!options.mapDiscardOnce) {
|
---|
374 | D3D11_MAP mapMode = drawIndex ? D3D11_MAP_WRITE_NO_OVERWRITE : D3D11_MAP_WRITE_DISCARD;
|
---|
375 | m_context->Map(m_cbVs.ptr(), 0, mapMode, 0, &sr);
|
---|
376 | auto vsData = reinterpret_cast<VsConstantsPad*>(sr.pData);
|
---|
377 | vsData[drawIndex].data = getVsConstants(x, baseY + y);
|
---|
378 | m_context->Unmap(m_cbVs.ptr(), 0);
|
---|
379 | }
|
---|
380 |
|
---|
381 | uint32_t constantOffset = 16 * drawIndex;
|
---|
382 | uint32_t constantCount = 16;
|
---|
383 | m_context->VSSetConstantBuffers1(0, 1, &m_cbVs, &constantOffset, &constantCount);
|
---|
384 |
|
---|
385 | if (!options.sortByTexture) {
|
---|
386 | ID3D11ShaderResourceView* view = triIndex ? m_srv1.ptr() : m_srv0.ptr();
|
---|
387 | m_context->PSSetShaderResources(0, 1, &view);
|
---|
388 | }
|
---|
389 |
|
---|
390 | // Submit draw call
|
---|
391 | uint32_t baseIndex = 3 * triIndex;
|
---|
392 |
|
---|
393 | if (options.drawIndexed)
|
---|
394 | m_context->DrawIndexed(3, baseIndex, 0);
|
---|
395 | else
|
---|
396 | m_context->Draw(3, baseIndex);
|
---|
397 |
|
---|
398 | drawIndex += maxZ;
|
---|
399 | }
|
---|
400 | }
|
---|
401 | }
|
---|
402 | }
|
---|
403 |
|
---|
404 |
|
---|
405 | static VsConstants getVsConstants(uint32_t x, uint32_t y) {
|
---|
406 | VsConstants result;
|
---|
407 | result.x = float(x) / 128.0f;
|
---|
408 | result.y = float(y) / 64.0f;
|
---|
409 | result.w = 1.0f / 128.0f;
|
---|
410 | result.h = 1.0f / 64.0f;
|
---|
411 | return result;
|
---|
412 | }
|
---|
413 |
|
---|
414 |
|
---|
415 | bool beginFrame() {
|
---|
416 | // Make sure we can actually render to the window
|
---|
417 | RECT windowRect = { 0, 0, 1024, 600 };
|
---|
418 | GetClientRect(m_window, &windowRect);
|
---|
419 |
|
---|
420 | uint32_t newWindowSizeW = uint32_t(windowRect.right - windowRect.left);
|
---|
421 | uint32_t newWindowSizeH = uint32_t(windowRect.bottom - windowRect.top);
|
---|
422 |
|
---|
423 | if (m_windowSizeW != newWindowSizeW || m_windowSizeH != newWindowSizeH) {
|
---|
424 | m_rtv = nullptr;
|
---|
425 | m_context->ClearState();
|
---|
426 |
|
---|
427 | DXGI_SWAP_CHAIN_DESC1 desc;
|
---|
428 | m_swapChain->GetDesc1(&desc);
|
---|
429 |
|
---|
430 | if (FAILED(m_swapChain->ResizeBuffers(desc.BufferCount,
|
---|
431 | newWindowSizeW, newWindowSizeH, desc.Format, desc.Flags))) {
|
---|
432 | std::cerr << "Failed to resize back buffers" << std::endl;
|
---|
433 | return false;
|
---|
434 | }
|
---|
435 |
|
---|
436 | Com<ID3D11Texture2D> backBuffer;
|
---|
437 | if (FAILED(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)))) {
|
---|
438 | std::cerr << "Failed to get swap chain back buffer" << std::endl;
|
---|
439 | return false;
|
---|
440 | }
|
---|
441 |
|
---|
442 | D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
|
---|
443 | rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
---|
444 | rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
---|
445 | rtvDesc.Texture2D = { 0u };
|
---|
446 |
|
---|
447 | if (FAILED(m_device->CreateRenderTargetView(backBuffer.ptr(), &rtvDesc, &m_rtv))) {
|
---|
448 | std::cerr << "Failed to create render target view" << std::endl;
|
---|
449 | return false;
|
---|
450 | }
|
---|
451 |
|
---|
452 | m_windowSizeW = newWindowSizeW;
|
---|
453 | m_windowSizeH = newWindowSizeH;
|
---|
454 | }
|
---|
455 |
|
---|
456 | // Set up render state
|
---|
457 | FLOAT color[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
---|
458 | m_context->OMSetRenderTargets(1, &m_rtv, nullptr);
|
---|
459 | m_context->ClearRenderTargetView(m_rtv.ptr(), color);
|
---|
460 |
|
---|
461 | m_context->VSSetShader(m_vs.ptr(), nullptr, 0);
|
---|
462 | m_context->PSSetShader(m_ps.ptr(), nullptr, 0);
|
---|
463 |
|
---|
464 | m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
---|
465 | m_context->IASetInputLayout(m_vertexFormat.ptr());
|
---|
466 |
|
---|
467 | D3D11_VIEWPORT viewport;
|
---|
468 | viewport.TopLeftX = 0.0f;
|
---|
469 | viewport.TopLeftY = 0.0f;
|
---|
470 | viewport.Width = float(m_windowSizeW);
|
---|
471 | viewport.Height = float(m_windowSizeH);
|
---|
472 | viewport.MinDepth = 0.0f;
|
---|
473 | viewport.MaxDepth = 1.0f;
|
---|
474 | m_context->RSSetViewports(1, &viewport);
|
---|
475 | return true;
|
---|
476 | }
|
---|
477 |
|
---|
478 |
|
---|
479 | bool endFrame() {
|
---|
480 | HRESULT hr = m_swapChain->Present(0, DXGI_PRESENT_TEST);
|
---|
481 |
|
---|
482 | if (hr == S_OK)
|
---|
483 | hr = m_swapChain->Present(0, 0);
|
---|
484 |
|
---|
485 | m_occluded = hr == DXGI_STATUS_OCCLUDED;
|
---|
486 | return true;
|
---|
487 | }
|
---|
488 |
|
---|
489 | void updateFps() {
|
---|
490 | if (!m_qpcFrequency.QuadPart)
|
---|
491 | QueryPerformanceFrequency(&m_qpcFrequency);
|
---|
492 |
|
---|
493 | if (!m_qpcLastUpdate.QuadPart)
|
---|
494 | QueryPerformanceCounter(&m_qpcLastUpdate);
|
---|
495 |
|
---|
496 | LARGE_INTEGER now;
|
---|
497 | QueryPerformanceCounter(&now);
|
---|
498 |
|
---|
499 | m_frameCount++;
|
---|
500 |
|
---|
501 | if (now.QuadPart - m_qpcLastUpdate.QuadPart < m_qpcFrequency.QuadPart)
|
---|
502 | return;
|
---|
503 |
|
---|
504 | double seconds = double(now.QuadPart - m_qpcLastUpdate.QuadPart) / double(m_qpcFrequency.QuadPart);
|
---|
505 | double fps = double(m_frameCount) / seconds;
|
---|
506 |
|
---|
507 | std::wstringstream str;
|
---|
508 | str << L"D3D11 triangle (" << fps << L" FPS)";
|
---|
509 |
|
---|
510 | SetWindowTextW(m_window, str.str().c_str());
|
---|
511 |
|
---|
512 | m_qpcLastUpdate = now;
|
---|
513 | m_frameCount = 0;
|
---|
514 | }
|
---|
515 |
|
---|
516 | bool isOccluded() {
|
---|
517 | return m_swapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED;
|
---|
518 | }
|
---|
519 |
|
---|
520 | private:
|
---|
521 |
|
---|
522 | HWND m_window;
|
---|
523 | uint32_t m_windowSizeW = 1024;
|
---|
524 | uint32_t m_windowSizeH = 600;
|
---|
525 | bool m_initialized = false;
|
---|
526 | bool m_occluded = false;
|
---|
527 |
|
---|
528 | Com<IDXGIFactory3> m_factory;
|
---|
529 | Com<IDXGIAdapter> m_adapter;
|
---|
530 | Com<ID3D11Device1> m_device;
|
---|
531 | Com<ID3D11DeviceContext1> m_context;
|
---|
532 | Com<IDXGISwapChain2> m_swapChain;
|
---|
533 |
|
---|
534 | Com<ID3D11RenderTargetView> m_rtv;
|
---|
535 | Com<ID3D11Buffer> m_ibo;
|
---|
536 | Com<ID3D11Buffer> m_vbo;
|
---|
537 | Com<ID3D11InputLayout> m_vertexFormat;
|
---|
538 |
|
---|
539 | Com<ID3D11Texture2D> m_tex0;
|
---|
540 | Com<ID3D11Texture2D> m_tex1;
|
---|
541 | Com<ID3D11ShaderResourceView> m_srv0;
|
---|
542 | Com<ID3D11ShaderResourceView> m_srv1;
|
---|
543 |
|
---|
544 | Com<ID3D11Buffer> m_cbPs;
|
---|
545 | Com<ID3D11Buffer> m_cbVs;
|
---|
546 |
|
---|
547 | Com<ID3D11VertexShader> m_vs;
|
---|
548 | Com<ID3D11PixelShader> m_ps;
|
---|
549 |
|
---|
550 | LARGE_INTEGER m_qpcLastUpdate = { };
|
---|
551 | LARGE_INTEGER m_qpcFrequency = { };
|
---|
552 |
|
---|
553 | uint32_t m_frameCount = 0;
|
---|
554 |
|
---|
555 | };
|
---|
556 |
|
---|
557 | LRESULT CALLBACK WindowProc(HWND hWnd,
|
---|
558 | UINT message,
|
---|
559 | WPARAM wParam,
|
---|
560 | LPARAM lParam);
|
---|
561 |
|
---|
562 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
---|
563 | WNDCLASSEXW wc = { };
|
---|
564 | wc.cbSize = sizeof(wc);
|
---|
565 | wc.style = CS_HREDRAW | CS_VREDRAW;
|
---|
566 | wc.lpfnWndProc = WindowProc;
|
---|
567 | wc.hInstance = hInstance;
|
---|
568 | wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
---|
569 | wc.hbrBackground = HBRUSH(COLOR_WINDOW);
|
---|
570 | wc.lpszClassName = L"WindowClass";
|
---|
571 | RegisterClassExW(&wc);
|
---|
572 |
|
---|
573 | HWND hWnd = CreateWindowExW(0, L"WindowClass", L"D3D11 triangle",
|
---|
574 | WS_OVERLAPPEDWINDOW, 300, 300, 1024, 600,
|
---|
575 | nullptr, nullptr, hInstance, nullptr);
|
---|
576 | ShowWindow(hWnd, nCmdShow);
|
---|
577 |
|
---|
578 | TriangleApp app(hInstance, hWnd);
|
---|
579 |
|
---|
580 | MSG msg;
|
---|
581 |
|
---|
582 | while (true) {
|
---|
583 | if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
---|
584 | TranslateMessage(&msg);
|
---|
585 | DispatchMessageW(&msg);
|
---|
586 |
|
---|
587 | if (msg.message == WM_QUIT)
|
---|
588 | return msg.wParam;
|
---|
589 | } else {
|
---|
590 | if (!app.run())
|
---|
591 | break;
|
---|
592 | }
|
---|
593 | }
|
---|
594 |
|
---|
595 | return msg.wParam;
|
---|
596 | }
|
---|
597 |
|
---|
598 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
---|
599 | switch (message) {
|
---|
600 | case WM_CLOSE:
|
---|
601 | PostQuitMessage(0);
|
---|
602 | return 0;
|
---|
603 | }
|
---|
604 |
|
---|
605 | return DefWindowProcW(hWnd, message, wParam, lParam);
|
---|
606 | }
|
---|