1#include "SwapChainD3D11.h"
3#include "FormatsD3D11.h"
4#include "GraphicsDeviceD3D11.h"
6#include "Foundation/Logging/Logger.h"
7#include "Foundation/Platform/WindowData.h"
13Cogs::SwapChainD3D11::SwapChainD3D11(GraphicsDeviceD3D11* device) : graphicsDevice(device) {
16Cogs::SwapChainD3D11::~SwapChainD3D11() {
22bool Cogs::SwapChainD3D11::initialize(WindowData* winData) {
26 const GraphicsDeviceSettings& settings = graphicsDevice->getSettings();
28 if (windowData->windowHandle) {
29 ResourcePointer<IDXGIDevice> dxgiDevice;
30 ResourcePointer<IDXGIAdapter> dxgiAdapter;
31 ResourcePointer<IDXGIFactory> dxgiFactory;
34 hr = graphicsDevice->getDevice()->QueryInterface(__uuidof(IDXGIDevice), dxgiDevice.internalVoidPointer());
36 LOG_FATAL(logger,
"Could not obtain IDXGIDevice from ID3D11Device: %s", direct3D11ReturnCodeAsString(hr));
40 hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), dxgiAdapter.internalVoidPointer());
42 LOG_FATAL(logger,
"Could not obtain IDXGIAdapter from IDXGIDevice: %s", direct3D11ReturnCodeAsString(hr));
46 hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), dxgiFactory.internalVoidPointer());
48 LOG_FATAL(logger,
"Could not obtain IDXGIFactory from IDXGIAdapter: %s", direct3D11ReturnCodeAsString(hr));
52 DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
54 swapChainDesc.BufferCount = 2;
55 swapChainDesc.BufferDesc.Width = this->width;
56 swapChainDesc.BufferDesc.Height = this->height;
57 swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
58 swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
59 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
60 swapChainDesc.OutputWindow = windowData->windowHandle;
61 swapChainDesc.SampleDesc.Quality = 0;
62 swapChainDesc.Windowed =
true;
63 swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
66 swapChainDesc.BufferDesc.Format =
Direct3D11::Formats[
static_cast<int>(settings.colorFormat)];
67 swapChainDesc.SampleDesc.Count = settings.numSamples;
68 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
71 switch (settings.colorFormat) {
72 case Format::R10G10B10A2_TYPELESS:
73 case Format::R10G10B10A2_UNORM:
74 case Format::R10G10B10A2_UINT: swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
break;
75 default: swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
77 swapChainDesc.SampleDesc.Count = 1;
78 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
81 hr = dxgiFactory->CreateSwapChain(graphicsDevice->getDevice(), &swapChainDesc, swapChain.internalPointer());
84 LOG_FATAL(logger,
"Error creating the swap chain: %s", direct3D11ReturnCodeAsString(hr));
88 hr = dxgiFactory->MakeWindowAssociation(windowData->windowHandle, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER);
91 LOG_WARNING(logger,
"Failed to associated DXGI with the window when creating the swap chain: %s", direct3D11ReturnCodeAsString(hr));
94 return recreateOffscreenBuffers() && createRenderTargetView() && createDepthStencilView();
109 if (swapChain && backBuffer) {
112 ID3D11DeviceContext* context;
114 graphicsDevice->getDevice()->GetImmediateContext(&context);
115 swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (
void**)&displayBuffer);
116 context->ResolveSubresource(displayBuffer, 0, backBuffer, 0,
Direct3D11::Formats[
static_cast<int>(colorFormat)]);
119 uint32_t dxPresentFlags = 0;
120 HRESULT hr = swapChain->Present(syncInterval, dxPresentFlags);
123 LOG_ERROR(logger,
"Present failed: 0x%x %s", hr, direct3D11ReturnCodeAsString(hr));
125 if (hr == DXGI_ERROR_DEVICE_REMOVED) {
126 hr = graphicsDevice->getDevice()->GetDeviceRemovedReason();
127 LOG_ERROR(logger,
"Removed Reason: 0x%x %s", hr, direct3D11ReturnCodeAsString(hr));
131 else if (sharedBackBuffer && backBuffer && (sharedBackBuffer != backBuffer)) {
132 ID3D11DeviceContext* context;
134 graphicsDevice->getDevice()->GetImmediateContext(&context);
136 if (sharedBackBuffer != backBuffer) {
137 D3D11_TEXTURE2D_DESC textureDesc;
138 D3D11_TEXTURE2D_DESC destD;
140 backBuffer->GetDesc(&textureDesc);
141 sharedBackBuffer->GetDesc(&destD);
142 context->ResolveSubresource(sharedBackBuffer, 0, backBuffer, 0, textureDesc.Format);
151 if (!isFullscreen()) {
152 if (forceIt || (newWidth != width) || (newHeight != height)) {
156 if (inFrame || !swapChain) {
171 if (enabled != isFullscreen()) {
172 if (enabled && needResize) {
176 swapChain->SetFullscreenState(enabled,
nullptr);
189 swapChain->GetFullscreenState(&state,
nullptr);
194void Cogs::SwapChainD3D11::resize() {
195 if (width && height) {
197 if (HandleIsValid(renderTarget)) {
198 graphicsDevice->getRenderTargets()->releaseRenderTarget(renderTarget);
203 DXGI_SWAP_CHAIN_DESC swapChainDesc;
205 swapChain->GetDesc(&swapChainDesc);
206 swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags);
209 recreateOffscreenBuffers();
212 graphicsDevice->resizeSharedSurfaces();
215 createRenderTargetView();
216 createDepthStencilView();
222bool Cogs::SwapChainD3D11::recreateOffscreenBuffers() {
223 sharedBackBuffer = {};
226 const GraphicsDeviceSettings& settings = graphicsDevice->getSettings();
228 D3D11_TEXTURE2D_DESC textureMsDesc;
230 textureMsDesc.Width = width;
231 textureMsDesc.Height = height;
232 textureMsDesc.MipLevels = 1;
233 textureMsDesc.ArraySize = 1;
234 textureMsDesc.Format = backBufferFormat;
235 textureMsDesc.SampleDesc.Count = settings.numSamples;
236 textureMsDesc.SampleDesc.Quality = 0;
237 textureMsDesc.Usage = D3D11_USAGE_DEFAULT;
238 textureMsDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
239 textureMsDesc.CPUAccessFlags = 0;
240 textureMsDesc.MiscFlags = 0;
242 HRESULT hr = graphicsDevice->getDevice()->CreateTexture2D(&textureMsDesc,
nullptr, backBuffer.internalPointer());
245 LOG_WARNING(logger,
"Failed to create multisampled off-screen back buffer. Falling back to regular surface: %s", direct3D11ReturnCodeAsString(hr));
249 D3D11_TEXTURE2D_DESC textureDesc;
251 textureDesc.Width = width;
252 textureDesc.Height = height;
253 textureDesc.MipLevels = 1;
254 textureDesc.ArraySize = 1;
255 textureDesc.Format = backBufferFormat;
256 textureDesc.SampleDesc.Count = 1;
257 textureDesc.SampleDesc.Quality = 0;
258 textureDesc.Usage = D3D11_USAGE_DEFAULT;
259 textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
260 textureDesc.CPUAccessFlags = 0;
261 textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
263 hr = graphicsDevice->getDevice()->CreateTexture2D(&textureDesc,
nullptr, sharedBackBuffer.internalPointer());
265 LOG_FATAL(logger,
"Failed to create off-screen back buffer: %s", direct3D11ReturnCodeAsString(hr));
271 backBuffer = sharedBackBuffer;
284 HRESULT hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), currentBackBuffer.internalVoidPointer());
287 LOG_ERROR(logger,
"Failed to create render target views: %s", direct3D11ReturnCodeAsString(hr));
292 currentBackBuffer = backBuffer;
297 if (HandleIsValid(renderTarget)) {
302 renderTarget = renderTargets->createRenderTarget(currentBackBuffer,
true);
312 if (HandleIsValid(depthStencil)) {
318 renderTargets->depthStencilViews.pin(depthStencil);
Log implementation class.
virtual void beginFrame() override
Signal the beginning of a new frame to the graphics device.
bool createDepthStencilView()
Recreates the depth/stencil view used by directx when rendering.
virtual void endFrame(uint32_t syncInterval=0, uint32_t presentFlags=PresentFlags::None) override
Signal the end of a frame to the graphics device.
virtual void setFullscreen(bool enabled) override
Changes this swapchain's fullscreen state if neccessary.
virtual bool isFullscreen() override
Test whether the current swap chain is fullscreen.
bool createRenderTargetView()
Recreates the render target view used by directx when selecting render targets prior to rendering.
virtual void setSize(int newWidth, int newHeight, bool forceIt=false) override
Set the size of the main drawing buffer used by the graphics device in pixels.
const DXGI_FORMAT Formats[]
Must match up to Format definition.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ UseSwapEffectDiscard
Under DX11 the default swap effect is FLIP_DISCARD, however there are some systems where this does no...
@ UseSharedSurface
Use shared surface for D3D9 interop.
static const Handle_t InvalidHandle
Represents an invalid handle.
@ NoSwap
Disables frame buffer swapping. This will leave the currently presented buffer as is.
void releaseRenderTarget(RenderTargetHandle handle)
Release the render target with the given renderTargetHandle.
DepthStencilHandle createDepthStencilTarget(const RenderTargetHandle handle, const DepthStencilViewDescription &depthStencilView)
Creates a depth stencil view using the given description.
void releaseDepthStencilTarget(DepthStencilHandle handle) override
Release the depth target with the given depthStencilHandle.