1#include "GraphicsDeviceD3D12.h"
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"
15Cogs::GraphicsDeviceD3D12::GraphicsDeviceD3D12(RenderingAllocatorInfo *) :
23Cogs::GraphicsDeviceD3D12::~GraphicsDeviceD3D12()
32 if (settings.ioHandler) effects.setIOHandler(settings.ioHandler);
34 return SUCCEEDED(this->initializeDevice());
37HRESULT Cogs::GraphicsDeviceD3D12::initializeDevice()
39 HRESULT hr = initializeDeviceAndSwapChain();
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);
52 this->context.initialize(
this);
54 hr = this->createRenderTargetView();
60 hr = this->createDepthStencilView();
62 waitForPreviousFrame();
67HRESULT Cogs::GraphicsDeviceD3D12::initializeDeviceAndSwapChain()
73 ResourcePointer<ID3D12Debug> debugController;
74 hr = D3D12GetDebugInterface(IID_PPV_ARGS(debugController.internalPointer()));
76 if (FAILED(hr) || !debugController) {
77 LOG_WARNING(logger,
"Failed to get debug interface.");
79 debugController->EnableDebugLayer();
84 D3D_DRIVER_TYPE driverTypes[] = {
85 D3D_DRIVER_TYPE_HARDWARE,
87 D3D_DRIVER_TYPE_REFERENCE,
90 UINT numDriverTypes =
sizeof(driverTypes) /
sizeof(driverTypes[0]);
92 DXGI_SWAP_CHAIN_DESC swapChainDesc{};
93 swapChainDesc.BufferCount = numSwapBufs;
95 if (format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) {
96 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
98 swapChainDesc.BufferDesc.Format = format;
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;
106 D3D_DRIVER_TYPE driverType;
108 for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) {
109 driverType = driverTypes[driverTypeIndex];
111 hr = D3D12CreateDevice(
113 D3D_FEATURE_LEVEL_12_0,
114 IID_PPV_ARGS(device.internalPointer())
117 ResourcePointer<ID3D12InfoQueue> infoQueue;
118 device->QueryInterface<ID3D12InfoQueue>(infoQueue.internalPointer());
121 infoQueue->SetMuteDebugOutput(
false);
122 infoQueue->SetBreakOnCategory(D3D12_MESSAGE_CATEGORY_CLEANUP,
true);
131 LOG_ERROR(logger,
"Could not create device.");
135 D3D12_FEATURE_DATA_D3D12_OPTIONS featureData;
136 hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &featureData,
sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS));
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.");
144 D3D12_COMMAND_QUEUE_DESC queueDesc{};
145 queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
146 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
148 hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(commandQueue.internalPointer()));
151 LOG_ERROR(logger,
"Could not create command queue.");
156 ResourcePointer<IDXGIFactory> dxgiFactory;
158 hr = CreateDXGIFactory1(IID_PPV_ARGS(dxgiFactory.internalPointer()));
161 LOG_ERROR(logger,
"Could not create DXGI factory.");
165 hr = dxgiFactory->CreateSwapChain(
168 swapChain.internalPointer()
172 LOG_ERROR(logger,
"Could not create swap chain.");
177 device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(deviceFence.internalPointer()));
180 eventHandle = CreateEventEx(
nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
187HRESULT Cogs::GraphicsDeviceD3D12::initializeDeviceShared()
189 LOG_ERROR(logger,
"Shared surface support not enabled. Enable D3D9 shared surface support.");
194HRESULT Cogs::GraphicsDeviceD3D12::resizeSharedSurfaces()
199HRESULT Cogs::GraphicsDeviceD3D12::createRenderTargetView()
201 if (settings.numSamples > 1) {
203 renderTargets.releaseRenderTarget(renderTarget[0]);
207 if (multisampleBackBuffer) {
208 context.currentFrameResources->orphanedResources.push_back(multisampleBackBuffer);
210 multisampleBackBuffer = {};
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;
226 if (FAILED(device->CreateCommittedResource(
227 &defaultHeapProperties,
228 D3D12_HEAP_FLAG_NONE,
230 D3D12_RESOURCE_STATE_COMMON,
232 IID_PPV_ARGS(multisampleBackBuffer.internalPointer())))) {
236 multisampleBackBuffer->AddRef();
239 if (multisampleBackBuffer) {
240 renderTarget[0] = renderTargets.createRenderTarget(multisampleBackBuffer);
242 for (
int i = 1; i < numSwapBufs; ++i) {
243 renderTarget[i] = renderTarget[0];
246 for (
int i = 0; i < numSwapBufs; ++i) {
247 ResourcePointer<ID3D12Resource> resource;
248 swapChain->GetBuffer(i, IID_PPV_ARGS(resource.internalPointer()));
250 renderTarget[i] = renderTargets.createRenderTarget(resource);
257HRESULT Cogs::GraphicsDeviceD3D12::createDepthStencilView()
260 renderTargets.releaseDepthStencilTarget(depthTarget);
261 textures.releaseTexture(depthTexture);
264 TextureFormat textureFormat = settings.depthFormat;
265 depthTexture = textures.loadTexture(
nullptr, width, height, textureFormat, settings.numSamples,
TextureFlags::DepthBuffer);
267 depthTarget = renderTargets.createDepthStencilTarget(renderTarget[0], depthTexture);
269 context.defaultDepthStencil = depthTarget;
276 auto currentRenderTarget = this->renderTarget[indexLastSwapBuf];
277 auto & renderTarget = renderTargets.renderTargets[currentRenderTarget];
278 context.defaultRenderTarget = currentRenderTarget;
280 context.updateFrameResources();
282 setResourceBarrier(context.commandList, renderTarget.resource, multisampleBackBuffer ? D3D12_RESOURCE_STATE_RESOLVE_SOURCE : D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
284 context.beginFrame();
289 ID3D12Resource * backBuffer;
290 swapChain->GetBuffer(indexLastSwapBuf, IID_PPV_ARGS(&backBuffer));
292 if (settings.numSamples > 1) {
293 auto & renderTarget = renderTargets.renderTargets[this->renderTarget[indexLastSwapBuf]];
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);
298 context.commandList->ResolveSubresource(backBuffer, 0, renderTarget.resource, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
300 setResourceBarrier(context.commandList, backBuffer, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PRESENT);
302 setResourceBarrier(context.commandList, backBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
307 swapChain->Present(verticalSync ? 1 : 0, 0);
309 indexLastSwapBuf = (1 + indexLastSwapBuf) % numSwapBufs;
312void Cogs::GraphicsDeviceD3D12::waitForPreviousFrame()
314 const UINT64 fence = currentFence;
315 commandQueue->Signal(deviceFence, fence);
318 if (deviceFence->GetCompletedValue() < fence)
320 deviceFence->SetEventOnCompletion(fence, eventHandle);
321 WaitForSingleObject(eventHandle, INFINITE);
327 if (width == this->width && height == this->height)
return;
330 this->height = height;
332 renderTargets.releaseDepthStencilTarget(depthTarget);
333 textures.releaseTexture(depthTexture);
336 if (settings.numSamples == 1) {
337 for (
int i = 0; i < numSwapBufs; ++i) {
338 renderTargets.releaseRenderTarget(renderTarget[i]);
343 swapChain->ResizeBuffers(numSwapBufs, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
345 createRenderTargetView();
346 createDepthStencilView();
Log implementation class.
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.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ 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.
static const Handle_t InvalidHandle
Represents an invalid handle.
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.