Cogs.Core
GraphicsDeviceD3D12.cpp
1#include "GraphicsDeviceD3D12.h"
2
3#include "BuffersD3D12.h"
4#include "TexturesD3D12.h"
5#include "ContextD3D12.h"
6#include "EffectsD3D12.h"
7#include "FormatsD3D12.h"
8#include "Foundation/Platform/WindowData.h"
9
10namespace
11{
12 Cogs::Logging::Log logger = Cogs::Logging::getLogger("GraphicsDeviceD3D12");
13}
14
15Cogs::GraphicsDeviceD3D12::GraphicsDeviceD3D12(RenderingAllocatorInfo *) :
16 verticalSync(false),
17 width(1260),
18 height(720)
19{
20
21}
22
23Cogs::GraphicsDeviceD3D12::~GraphicsDeviceD3D12()
24{
25 context.destroy();
26
27 // Shared resources are freed by unique_ptr destructor.
28}
29
31{
32 if (settings.ioHandler) effects.setIOHandler(settings.ioHandler);
33
34 return SUCCEEDED(this->initializeDevice());
35}
36
37HRESULT Cogs::GraphicsDeviceD3D12::initializeDevice()
38{
39 HRESULT hr = initializeDeviceAndSwapChain();
40
41 if (FAILED(hr)) {
42 return hr;
43 }
44
45 this->capabilities.initialize(device);
46 syncObjects.setDevice(device);
47 this->buffers.initialize(this);
48 this->textures.setDevice(this->device);
49 this->effects.setDevice(this->device, this);
50 this->renderTargets.initialize(this);
51
52 this->context.initialize(this);
53
54 hr = this->createRenderTargetView();
55
56 if (FAILED(hr)) {
57 return hr;
58 }
59
60 hr = this->createDepthStencilView();
61
62 waitForPreviousFrame();
63
64 return hr;
65}
66
67HRESULT Cogs::GraphicsDeviceD3D12::initializeDeviceAndSwapChain()
68{
69 HRESULT hr = S_OK;
70
71 {
72 if (isDebug() || ((settings.flags & GraphicsDeviceFlags::Debug) == GraphicsDeviceFlags::Debug)) {
73 ResourcePointer<ID3D12Debug> debugController;
74 hr = D3D12GetDebugInterface(IID_PPV_ARGS(debugController.internalPointer()));
75
76 if (FAILED(hr) || !debugController) {
77 LOG_WARNING(logger, "Failed to get debug interface.");
78 } else {
79 debugController->EnableDebugLayer();
80 }
81 }
82 }
83
84 D3D_DRIVER_TYPE driverTypes[] = {
85 D3D_DRIVER_TYPE_HARDWARE,
86 D3D_DRIVER_TYPE_WARP,
87 D3D_DRIVER_TYPE_REFERENCE,
88 };
89
90 UINT numDriverTypes = sizeof(driverTypes) / sizeof(driverTypes[0]);
91
92 DXGI_SWAP_CHAIN_DESC swapChainDesc{};
93 swapChainDesc.BufferCount = numSwapBufs;
94 auto format = Direct3D12::Formats[(int)settings.colorFormat];
95 if (format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) {
96 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
97 } else {
98 swapChainDesc.BufferDesc.Format = format;
99 }
100 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
101 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
102 swapChainDesc.OutputWindow = settings.windowData->windowHandle;
103 swapChainDesc.SampleDesc.Count = 1;
104 swapChainDesc.Windowed = TRUE;
105
106 D3D_DRIVER_TYPE driverType;
107
108 for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) {
109 driverType = driverTypes[driverTypeIndex];
110
111 hr = D3D12CreateDevice(
112 nullptr,
113 D3D_FEATURE_LEVEL_12_0,
114 IID_PPV_ARGS(device.internalPointer())
115 );
116
117 ResourcePointer<ID3D12InfoQueue> infoQueue;
118 device->QueryInterface<ID3D12InfoQueue>(infoQueue.internalPointer());
119
120 if (infoQueue) {
121 infoQueue->SetMuteDebugOutput(false);
122 infoQueue->SetBreakOnCategory(D3D12_MESSAGE_CATEGORY_CLEANUP, true);
123 }
124
125 if (SUCCEEDED(hr)) {
126 break;
127 }
128 }
129
130 if (FAILED(hr)) {
131 LOG_ERROR(logger, "Could not create device.");
132 return hr;
133 }
134
135 D3D12_FEATURE_DATA_D3D12_OPTIONS featureData;
136 hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &featureData, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS));
137
138 if (FAILED(hr) || featureData.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) {
139 LOG_ERROR(logger, "Resource binding tier 1 not supported. Check hardware or drivers installed.");
140
141 return E_FAIL;
142 }
143
144 D3D12_COMMAND_QUEUE_DESC queueDesc{};
145 queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
146 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
147
148 hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(commandQueue.internalPointer()));
149
150 if (FAILED(hr)) {
151 LOG_ERROR(logger, "Could not create command queue.");
152 return hr;
153 }
154
155 {
156 ResourcePointer<IDXGIFactory> dxgiFactory;
157
158 hr = CreateDXGIFactory1(IID_PPV_ARGS(dxgiFactory.internalPointer()));
159
160 if (FAILED(hr)) {
161 LOG_ERROR(logger, "Could not create DXGI factory.");
162 return hr;
163 }
164
165 hr = dxgiFactory->CreateSwapChain(
166 commandQueue, // Swap chain needs the queue so it can force a flush on it
167 &swapChainDesc,
168 swapChain.internalPointer()
169 );
170
171 if (FAILED(hr)) {
172 LOG_ERROR(logger, "Could not create swap chain.");
173 return hr;
174 }
175 }
176
177 device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(deviceFence.internalPointer()));
178 currentFence = 1;
179
180 eventHandle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
181
182 return hr;
183}
184
185
186
187HRESULT Cogs::GraphicsDeviceD3D12::initializeDeviceShared()
188{
189 LOG_ERROR(logger, "Shared surface support not enabled. Enable D3D9 shared surface support.");
190
191 return E_FAIL;
192}
193
194HRESULT Cogs::GraphicsDeviceD3D12::resizeSharedSurfaces()
195{
196 return E_FAIL;
197}
198
199HRESULT Cogs::GraphicsDeviceD3D12::createRenderTargetView()
200{
201 if (settings.numSamples > 1) {
202 if (HandleIsValid(renderTarget[0])) {
203 renderTargets.releaseRenderTarget(renderTarget[0]);
204 renderTarget[0] = RenderTargetHandle::NoHandle;
205 }
206
207 if (multisampleBackBuffer) {
208 context.currentFrameResources->orphanedResources.push_back(multisampleBackBuffer);
209
210 multisampleBackBuffer = {};
211 }
212
213 D3D12_RESOURCE_DESC textureDesc;
214 textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
215 textureDesc.DepthOrArraySize = static_cast<UINT16>(1);
216 textureDesc.Alignment = 0;
217 textureDesc.Width = width;
218 textureDesc.Height = height;
219 textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
220 textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
221 textureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
222 textureDesc.MipLevels = static_cast<UINT16>(1);
223 textureDesc.SampleDesc.Count = settings.numSamples;
224 textureDesc.SampleDesc.Quality = 0;
225
226 if (FAILED(device->CreateCommittedResource(
227 &defaultHeapProperties,
228 D3D12_HEAP_FLAG_NONE,
229 &textureDesc,
230 D3D12_RESOURCE_STATE_COMMON,
231 nullptr,
232 IID_PPV_ARGS(multisampleBackBuffer.internalPointer())))) {
233 return E_FAIL;
234 }
235
236 multisampleBackBuffer->AddRef();
237 }
238
239 if (multisampleBackBuffer) {
240 renderTarget[0] = renderTargets.createRenderTarget(multisampleBackBuffer);
241
242 for (int i = 1; i < numSwapBufs; ++i) {
243 renderTarget[i] = renderTarget[0];
244 }
245 } else {
246 for (int i = 0; i < numSwapBufs; ++i) {
247 ResourcePointer<ID3D12Resource> resource;
248 swapChain->GetBuffer(i, IID_PPV_ARGS(resource.internalPointer()));
249
250 renderTarget[i] = renderTargets.createRenderTarget(resource);
251 }
252 }
253
254 return S_OK;
255}
256
257HRESULT Cogs::GraphicsDeviceD3D12::createDepthStencilView()
258{
259 if (HandleIsValid(depthTarget)) {
260 renderTargets.releaseDepthStencilTarget(depthTarget);
261 textures.releaseTexture(depthTexture);
262 }
263
264 TextureFormat textureFormat = settings.depthFormat;
265 depthTexture = textures.loadTexture(nullptr, width, height, textureFormat, settings.numSamples, TextureFlags::DepthBuffer);
266
267 depthTarget = renderTargets.createDepthStencilTarget(renderTarget[0], depthTexture);
268
269 context.defaultDepthStencil = depthTarget;
270
271 return S_OK;
272}
273
275{
276 auto currentRenderTarget = this->renderTarget[indexLastSwapBuf];
277 auto & renderTarget = renderTargets.renderTargets[currentRenderTarget];
278 context.defaultRenderTarget = currentRenderTarget;
279
280 context.updateFrameResources();
281
282 setResourceBarrier(context.commandList, renderTarget.resource, multisampleBackBuffer ? D3D12_RESOURCE_STATE_RESOLVE_SOURCE : D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
283
284 context.beginFrame();
285}
286
287void Cogs::GraphicsDeviceD3D12::endFrame(uint32_t syncInterval, uint32_t presentFlags)
288{
289 ID3D12Resource * backBuffer;
290 swapChain->GetBuffer(indexLastSwapBuf, IID_PPV_ARGS(&backBuffer));
291
292 if (settings.numSamples > 1) {
293 auto & renderTarget = renderTargets.renderTargets[this->renderTarget[indexLastSwapBuf]];
294
295 setResourceBarrier(context.commandList, renderTarget.resource, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
296 setResourceBarrier(context.commandList, backBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RESOLVE_DEST);
297
298 context.commandList->ResolveSubresource(backBuffer, 0, renderTarget.resource, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
299
300 setResourceBarrier(context.commandList, backBuffer, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PRESENT);
301 } else {
302 setResourceBarrier(context.commandList, backBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
303 }
304
305 context.endFrame();
306
307 swapChain->Present(verticalSync ? 1 : 0, 0);
308
309 indexLastSwapBuf = (1 + indexLastSwapBuf) % numSwapBufs;
310}
311
312void Cogs::GraphicsDeviceD3D12::waitForPreviousFrame()
313{
314 const UINT64 fence = currentFence;
315 commandQueue->Signal(deviceFence, fence);
316 currentFence++;
317
318 if (deviceFence->GetCompletedValue() < fence)
319 {
320 deviceFence->SetEventOnCompletion(fence, eventHandle);
321 WaitForSingleObject(eventHandle, INFINITE);
322 }
323}
324
325void Cogs::GraphicsDeviceD3D12::setSize(int width, int height)
326{
327 if (width == this->width && height == this->height) return;
328
329 this->width = width;
330 this->height = height;
331
332 renderTargets.releaseDepthStencilTarget(depthTarget);
333 textures.releaseTexture(depthTexture);
335
336 if (settings.numSamples == 1) {
337 for (int i = 0; i < numSwapBufs; ++i) {
338 renderTargets.releaseRenderTarget(renderTarget[i]);
339 renderTarget[i] = RenderTargetHandle::InvalidHandle;
340 }
341 }
342
343 swapChain->ResizeBuffers(numSwapBufs, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
344
345 createRenderTargetView();
346 createDepthStencilView();
347}
348
349bool Cogs::GraphicsDeviceD3D12::getSize(int& w, int& h) const
350{
351 w = this->width;
352 h = this->height;
353 return true;
354}
355
356
358{
359
360}
361
363{
364 /*this->effects.releaseResources();
365 this->renderTargets.releaseResources();
366 this->textures.releaseResources();
367 this->buffers.releaseResources();*/
368}
Log implementation class.
Definition: LogManager.h:139
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
const DXGI_FORMAT Formats[]
Must match up to Format definition.
Definition: FormatsD3D12.cpp:9
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ Debug
If available, the device will operate in debug mode, performing additional validation of input data,...
void waitForCommandSync() override
Wait for any GPU commands on the current device to finish before returning.
void beginFrame() override
Signal the beginning of a new frame to the graphics device.
bool initialize()
Initializes the graphics device with the settings previous set through calling setSettings.
void releaseResources() override
Release all resources allocated.
void endFrame(uint32_t syncInterval=0, uint32_t presentFlags=PresentFlags::None) override
Signal the end of a frame to the graphics device.
void setSize(int width, int height) override
Set the size of the main drawing buffer used by the graphics device in pixels.
bool getSize(int &w, int &h) const override
Retrieve the size previously set by setSize.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
Definition: Flags.h:122