From 97b32f52cc123544a1352527c2509c804fd3d190 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Mon, 12 Aug 2019 22:00:42 -0700 Subject: D3D12 backend: enabled multiple swap chain support --- Graphics/GraphicsEngine/include/SwapChainBase.h | 50 +++++++++++++++++++-- Graphics/GraphicsEngine/interface/SwapChain.h | 3 ++ .../GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp | 2 +- .../GraphicsEngineD3D11/src/SwapChainD3D11Impl.cpp | 52 +++------------------- .../GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp | 48 ++++++++++++-------- .../GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp | 25 ++++++----- 6 files changed, 101 insertions(+), 79 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsEngine/include/SwapChainBase.h b/Graphics/GraphicsEngine/include/SwapChainBase.h index 8b9aa86f..5a60c9ed 100644 --- a/Graphics/GraphicsEngine/include/SwapChainBase.h +++ b/Graphics/GraphicsEngine/include/SwapChainBase.h @@ -26,6 +26,8 @@ /// \file /// Implementation of the Diligent::SwapChainBase template class +#include + #include "RenderDevice.h" #include "DeviceContext.h" #include "SwapChain.h" @@ -89,13 +91,55 @@ protected: return false; } - + + template + bool UnbindRenderTargets(DeviceContextImplType* pImmediateCtx, + ITextureView* ppBackBufferRTVs[], + Uint32 NumBackBufferRTVs, + ITextureView* pDSV) + { + bool RebindRenderTargets = false; + bool UnbindRenderTargets = false; + if (m_SwapChainDesc.IsPrimary) + { + RebindRenderTargets = UnbindRenderTargets = pImmediateCtx->IsDefaultFBBound(); + } + else + { + std::array pBoundRTVs = {}; + RefCntAutoPtr pBoundDSV; + Uint32 NumRenderTargets = 0; + pImmediateCtx->GetRenderTargets(NumRenderTargets, pBoundRTVs.data(), &pBoundDSV); + for (Uint32 i=0; i < NumRenderTargets; ++i) + { + for (Uint32 j=0; j < NumBackBufferRTVs; ++j) + { + if (pBoundRTVs[i] == ppBackBufferRTVs[j]) + UnbindRenderTargets = true; + } + } + if (pBoundDSV == pDSV) + UnbindRenderTargets = true; + + for (auto pRTV : pBoundRTVs) + { + if (pRTV != nullptr) + pRTV->Release(); + } + } + + if (UnbindRenderTargets) + pImmediateCtx->ResetRenderTargets(); + + return RebindRenderTargets; + } + /// Strong reference to the render device - Diligent::RefCntAutoPtr m_pRenderDevice; + RefCntAutoPtr m_pRenderDevice; /// Weak references to the immediate device context. The context holds /// the strong reference to the swap chain. - Diligent::RefCntWeakPtr m_wpDeviceContext; + RefCntWeakPtr m_wpDeviceContext; /// Swap chain description SwapChainDesc m_SwapChainDesc; diff --git a/Graphics/GraphicsEngine/interface/SwapChain.h b/Graphics/GraphicsEngine/interface/SwapChain.h index 5e780292..164608e1 100644 --- a/Graphics/GraphicsEngine/interface/SwapChain.h +++ b/Graphics/GraphicsEngine/interface/SwapChain.h @@ -54,6 +54,9 @@ public: /// \param [in] NewWidth - New swap chain width, in pixels /// \param [in] NewHeight - New swap chain height, in pixels + /// + /// \note When resizing non-primary swap chains, the engine unbinds the + /// swap chain buffers from the output. virtual void Resize( Uint32 NewWidth, Uint32 NewHeight ) = 0; /// Sets fullscreen mode (only supported on Win32 platform) diff --git a/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp index 40a3eb16..87ffbdc5 100644 --- a/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp @@ -315,7 +315,7 @@ void EngineFactoryD3D11Impl::CreateSwapChainD3D11(IRenderDevice* pDev if (pDeviceContextD3D11->GetSwapChain() != nullptr && SCDesc.IsPrimary) { LOG_ERROR_AND_THROW("Another swap chain labeled as primary has already been created. " - "There must be only one primary swap chain."); + "There must only be one primary swap chain."); } auto* pSwapChainD3D11 = NEW_RC_OBJ(RawMemAllocator, "SwapChainD3D11Impl instance", SwapChainD3D11Impl) diff --git a/Graphics/GraphicsEngineD3D11/src/SwapChainD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/SwapChainD3D11Impl.cpp index 225e3a98..0ffc8070 100644 --- a/Graphics/GraphicsEngineD3D11/src/SwapChainD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/SwapChainD3D11Impl.cpp @@ -21,7 +21,6 @@ * of the possibility of such damages. */ -#include #include "pch.h" #include "SwapChainD3D11Impl.h" #include "RenderDeviceD3D11Impl.h" @@ -144,38 +143,9 @@ void SwapChainD3D11Impl::UpdateSwapChain(bool CreateNew) VERIFY(pDeviceContext, "Immediate context has been released"); if (pDeviceContext) { - auto *pImmediateCtxD3D11 = pDeviceContext.RawPtr(); - bool RebindRenderTargets = false; - bool UnbindRenderTargets = false; - if (m_SwapChainDesc.IsPrimary) - { - RebindRenderTargets = UnbindRenderTargets = pImmediateCtxD3D11->IsDefaultFBBound(); - } - else - { - std::array pOrigRTVs = {}; - RefCntAutoPtr pOrigDSV; - Uint32 NumRenderTargets = 0; - pImmediateCtxD3D11->GetRenderTargets(NumRenderTargets, pOrigRTVs.data(), &pOrigDSV); - for (Uint32 i=0; i < NumRenderTargets; ++i) - { - if (pOrigRTVs[i] == m_pRenderTargetView) - UnbindRenderTargets = true; - } - if (pOrigDSV == m_pDepthStencilView) - UnbindRenderTargets = true; - - RebindRenderTargets = NumRenderTargets == 1 && pOrigRTVs[0] == m_pRenderTargetView && pOrigDSV == m_pDepthStencilView; - - for(auto pRTV : pOrigRTVs) - { - if (pRTV != nullptr) - pRTV->Release(); - } - } - - if (UnbindRenderTargets) - pImmediateCtxD3D11->ResetRenderTargets(); + auto* pImmediateCtxD3D11 = pDeviceContext.RawPtr(); + ITextureView* pBackBufferRTVs[] = {m_pRenderTargetView}; + bool RebindRenderTargets = UnbindRenderTargets(pImmediateCtxD3D11, pBackBufferRTVs, 1, m_pDepthStencilView); // Swap chain cannot be resized until all references are released m_pRenderTargetView.Release(); @@ -214,19 +184,11 @@ void SwapChainD3D11Impl::UpdateSwapChain(bool CreateNew) CreateRTVandDSV(); - if (RebindRenderTargets) + if (m_SwapChainDesc.IsPrimary && RebindRenderTargets) { - if (m_SwapChainDesc.IsPrimary) - { - // Set default render target and viewport - pImmediateCtxD3D11->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - pImmediateCtxD3D11->SetViewports(1, nullptr, 0, 0); - } - else - { - ITextureView* pRTVs[] = {GetCurrentBackBufferRTV()}; - pImmediateCtxD3D11->SetRenderTargets(1, pRTVs, GetDepthBufferDSV(), RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - } + // Set default render target and viewport + pImmediateCtxD3D11->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + pImmediateCtxD3D11->SetViewports(1, nullptr, 0, 0); } } catch (const std::runtime_error &) diff --git a/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp index 53ede9e3..3c20c1bc 100644 --- a/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp @@ -367,29 +367,39 @@ void EngineFactoryD3D12Impl::CreateSwapChainD3D12(IRenderDevice* pDev try { - auto *pDeviceD3D12 = ValidatedCast( pDevice ); - auto *pDeviceContextD3D12 = ValidatedCast(pImmediateContext); - auto &RawMemAllocator = GetRawAllocator(); - auto *pSwapChainD3D12 = NEW_RC_OBJ(RawMemAllocator, "SwapChainD3D12Impl instance", SwapChainD3D12Impl)(SCDesc, FSDesc, pDeviceD3D12, pDeviceContextD3D12, pNativeWndHandle); + auto* pDeviceD3D12 = ValidatedCast( pDevice ); + auto* pDeviceContextD3D12 = ValidatedCast(pImmediateContext); + auto& RawMemAllocator = GetRawAllocator(); + + if (pDeviceContextD3D12->GetSwapChain() != nullptr && SCDesc.IsPrimary) + { + LOG_ERROR_AND_THROW("Another swap chain labeled as primary has already been created. " + "There must only be one primary swap chain."); + } + + auto* pSwapChainD3D12 = NEW_RC_OBJ(RawMemAllocator, "SwapChainD3D12Impl instance", SwapChainD3D12Impl)(SCDesc, FSDesc, pDeviceD3D12, pDeviceContextD3D12, pNativeWndHandle); pSwapChainD3D12->QueryInterface( IID_SwapChain, reinterpret_cast(ppSwapChain) ); - pDeviceContextD3D12->SetSwapChain(pSwapChainD3D12); - // Bind default render target - pDeviceContextD3D12->SetRenderTargets( 0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); - // Set default viewport - pDeviceContextD3D12->SetViewports( 1, nullptr, 0, 0 ); - - auto NumDeferredCtx = pDeviceD3D12->GetNumDeferredContexts(); - for (size_t ctx = 0; ctx < NumDeferredCtx; ++ctx) + if (SCDesc.IsPrimary) { - if (auto pDeferredCtx = pDeviceD3D12->GetDeferredContext(ctx)) + pDeviceContextD3D12->SetSwapChain(pSwapChainD3D12); + // Bind default render target + pDeviceContextD3D12->SetRenderTargets( 0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); + // Set default viewport + pDeviceContextD3D12->SetViewports( 1, nullptr, 0, 0 ); + + auto NumDeferredCtx = pDeviceD3D12->GetNumDeferredContexts(); + for (size_t ctx = 0; ctx < NumDeferredCtx; ++ctx) { - auto* pDeferredCtxD3D12 = pDeferredCtx.RawPtr(); - pDeferredCtxD3D12->SetSwapChain(pSwapChainD3D12); - // We cannot bind default render target here because - // there is no guarantee that deferred context will be used - // in this frame. It is an error to bind - // RTV of an inactive buffer in the swap chain + if (auto pDeferredCtx = pDeviceD3D12->GetDeferredContext(ctx)) + { + auto* pDeferredCtxD3D12 = pDeferredCtx.RawPtr(); + pDeferredCtxD3D12->SetSwapChain(pSwapChainD3D12); + // We cannot bind default render target here because + // there is no guarantee that deferred context will be used + // in this frame. It is an error to bind + // RTV of an inactive buffer in the swap chain + } } } } diff --git a/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp index c9e986b4..8658d649 100644 --- a/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp @@ -111,7 +111,7 @@ void SwapChainD3D12Impl::Present(Uint32 SyncInterval) #endif auto pDeviceContext = m_wpDeviceContext.Lock(); - if( !pDeviceContext ) + if (!pDeviceContext) { LOG_ERROR_MESSAGE( "Immediate context has been released" ); return; @@ -120,18 +120,20 @@ void SwapChainD3D12Impl::Present(Uint32 SyncInterval) auto* pImmediateCtxD3D12 = pDeviceContext.RawPtr(); auto& CmdCtx = pImmediateCtxD3D12->GetCmdContext(); - auto* pBackBuffer = ValidatedCast( GetCurrentBackBufferRTV()->GetTexture() ); + auto* pBackBuffer = ValidatedCast(GetCurrentBackBufferRTV()->GetTexture()); CmdCtx.TransitionResource(pBackBuffer, RESOURCE_STATE_PRESENT); pImmediateCtxD3D12->Flush(); - auto *pDeviceD3D12 = ValidatedCast( pImmediateCtxD3D12->GetDevice() ); - auto hr = m_pSwapChain->Present( SyncInterval, 0 ); VERIFY(SUCCEEDED(hr), "Present failed"); - pImmediateCtxD3D12->FinishFrame(); - pDeviceD3D12->ReleaseStaleResources(); + if (m_SwapChainDesc.IsPrimary) + { + pImmediateCtxD3D12->FinishFrame(); + auto* pDeviceD3D12 = ValidatedCast( pImmediateCtxD3D12->GetDevice() ); + pDeviceD3D12->ReleaseStaleResources(); + } #if 0 #if PLATFORM_UNIVERSAL_WINDOWS @@ -160,10 +162,11 @@ void SwapChainD3D12Impl::UpdateSwapChain(bool CreateNew) try { - auto *pImmediateCtxD3D12 = pDeviceContext.RawPtr(); - bool bIsDefaultFBBound = pImmediateCtxD3D12->IsDefaultFBBound(); - if(bIsDefaultFBBound) - pImmediateCtxD3D12->ResetRenderTargets(); + auto* pImmediateCtxD3D12 = pDeviceContext.RawPtr(); + std::vector pBackBufferRTVs(m_pBackBufferRTV.size()); + for(size_t i=0; i < m_pBackBufferRTV.size(); ++i) + pBackBufferRTVs[i] = m_pBackBufferRTV[i]; + bool RebindRenderTargets = UnbindRenderTargets(pImmediateCtxD3D12, pBackBufferRTVs.data(), static_cast(m_pBackBufferRTV.size()), m_pDepthBufferDSV); // All references to the swap chain must be released before it can be resized m_pBackBufferRTV.clear(); @@ -196,7 +199,7 @@ void SwapChainD3D12Impl::UpdateSwapChain(bool CreateNew) InitBuffersAndViews(); - if (bIsDefaultFBBound) + if (m_SwapChainDesc.IsPrimary && RebindRenderTargets) { // Set default render target and viewport pDeviceContext->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); -- cgit v1.2.3