From c32095993f3e5734b3b6a112aeef0a9536db8f7d Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 19 Dec 2019 10:11:08 -0800 Subject: Added ClearRenderTarget test; fixed issue with bound render targets in D3D12 and Vk backends --- .../GraphicsEngine/include/DeviceContextBase.h | 80 +++++++++++++++++++++- .../include/DeviceContextD3D11Impl.h | 2 +- .../src/DeviceContextD3D12Impl.cpp | 7 ++ .../include/DeviceContextVkImpl.h | 3 +- .../src/DeviceContextVkImpl.cpp | 12 +++- 5 files changed, 98 insertions(+), 6 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.h b/Graphics/GraphicsEngine/include/DeviceContextBase.h index c822dacf..d357c4f6 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.h +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.h @@ -190,7 +190,7 @@ public: /// Returns the render device IRenderDevice* GetDevice() { return m_pDevice; } - inline void ResetRenderTargets(); + virtual void ResetRenderTargets(); bool IsDeferred() const { return m_bIsDeferred; } @@ -204,6 +204,17 @@ protected: /// Clears all cached resources inline void ClearStateCache(); + /// Checks if the texture is currently bound as a render target. + bool CheckIfBoundAsRenderTarget(TextureImplType* pTexture); + + /// Checks if the texture is currently bound as depth-stencil buffer. + bool CheckIfBoundAsDepthStencil(TextureImplType* pTexture); + + /// Checks if the texture is bound as a render target or depth-stencil buffer and + /// resets render targets if it is. + bool UnbindTextureFromFramebuffer(TextureImplType* pTexture, bool bShowMessage); + + #ifdef DEVELOPMENT // clang-format off bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const; @@ -722,7 +733,72 @@ inline void DeviceContextBase::ClearStateCa } template -inline void DeviceContextBase::ResetRenderTargets() +bool DeviceContextBase::CheckIfBoundAsRenderTarget(TextureImplType* pTexture) +{ + if (pTexture == nullptr) + return false; + + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) + { + if (m_pBoundRenderTargets[rt] && m_pBoundRenderTargets[rt]->GetTexture() == pTexture) + { + return true; + } + } + + return false; +} + +template +bool DeviceContextBase::CheckIfBoundAsDepthStencil(TextureImplType* pTexture) +{ + if (pTexture == nullptr) + return false; + + return m_pBoundDepthStencil && m_pBoundDepthStencil->GetTexture() == pTexture; +} + +template +bool DeviceContextBase::UnbindTextureFromFramebuffer(TextureImplType* pTexture, bool bShowMessage) +{ + if (pTexture == nullptr) + return false; + + if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_RENDER_TARGET) && !pTexture->CheckState(RESOURCE_STATE_DEPTH_WRITE)) + return false; + + bool bResetRenderTargets = false; + if (CheckIfBoundAsRenderTarget(pTexture)) + { + if (bShowMessage) + { + LOG_INFO_MESSAGE("Texture '", pTexture->GetDesc().Name, + "' is currently bound as render target and will be unset along with all " + "other render targets and depth-stencil buffer. " + "Call SetRenderTargets() to reset the render targets."); + } + + bResetRenderTargets = true; + } + else if (CheckIfBoundAsDepthStencil(pTexture)) + { + LOG_INFO_MESSAGE("Texture '", pTexture->GetDesc().Name, + "' is currently bound as depth buffer and will be unset along with " + "all render targets. Call SetRenderTargets() to reset the render targets."); + + bResetRenderTargets = true; + } + + if (bResetRenderTargets) + { + ResetRenderTargets(); + } + + return bResetRenderTargets; +} + +template +void DeviceContextBase::ResetRenderTargets() { for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) m_pBoundRenderTargets[rt].Release(); diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h index d455fc85..1ec8f096 100755 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h @@ -221,7 +221,7 @@ public: void ReleaseCommittedShaderResources(); /// Unbinds all render targets. Used when resizing the swap chain. - void ResetRenderTargets(); + virtual void ResetRenderTargets() override final; /// Number of different shader types (Vertex, Pixel, Geometry, Domain, Hull, Compute) static constexpr int NumShaderTypes = 6; diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 5b5b10cb..7812afe0 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -1260,6 +1260,13 @@ void DeviceContextD3D12Impl::CopyTextureRegion(TextureD3D12Impl* pS Uint32 DstZ, RESOURCE_STATE_TRANSITION_MODE DstTextureTransitionMode) { + // We must unbind the textures from framebuffer because + // we will transition their states. If we later try to commit + // them as render targets (e.g. from SetPipelineState()), a + // state mismatch error will occur. + UnbindTextureFromFramebuffer(pSrcTexture, true); + UnbindTextureFromFramebuffer(pDstTexture, true); + auto& CmdCtx = GetCmdContext(); if (pSrcTexture->GetDesc().Usage == USAGE_STAGING) { diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index aa4085f1..7430ee9a 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -295,7 +295,8 @@ public: VulkanDynamicAllocation AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment); - void ResetRenderTargets(); + virtual void ResetRenderTargets() override final; + Int64 GetContextFrameNumber() const { return m_ContextFrameNumber; } GenerateMipsVkHelper& GetGenerateMipsHelper() { return *m_GenerateMipsHelper; } diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 135b5844..165f3bdd 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1407,8 +1407,16 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) { TDeviceContextBase::CopyTexture(CopyAttribs); - auto* pSrcTexVk = ValidatedCast(CopyAttribs.pSrcTexture); - auto* pDstTexVk = ValidatedCast(CopyAttribs.pDstTexture); + auto* pSrcTexVk = ValidatedCast(CopyAttribs.pSrcTexture); + auto* pDstTexVk = ValidatedCast(CopyAttribs.pDstTexture); + + // We must unbind the textures from framebuffer because + // we will transition their states. If we later try to commit + // them as render targets (e.g. from SetPipelineState()), a + // state mismatch error will occur. + UnbindTextureFromFramebuffer(pSrcTexVk, true); + UnbindTextureFromFramebuffer(pDstTexVk, true); + const auto& SrcTexDesc = pSrcTexVk->GetDesc(); const auto& DstTexDesc = pDstTexVk->GetDesc(); auto* pSrcBox = CopyAttribs.pSrcBox; -- cgit v1.2.3