From 37ec162b6eb08a3234801a3891fff4b58f0aaa6d Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sun, 2 Dec 2018 16:45:32 -0800 Subject: Improved state transition handling in D3D12 backend --- .../GraphicsEngineD3D12/include/CommandContext.h | 26 +++- .../GraphicsEngineD3D12/src/CommandContext.cpp | 151 --------------------- .../src/DeviceContextD3D12Impl.cpp | 87 ++++++++++-- 3 files changed, 96 insertions(+), 168 deletions(-) (limited to 'Graphics/GraphicsEngineD3D12') diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.h b/Graphics/GraphicsEngineD3D12/include/CommandContext.h index 159d6f0f..c3f33491 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.h +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.h @@ -75,8 +75,17 @@ public: class GraphicsContext& AsGraphicsContext(); class ComputeContext& AsComputeContext(); - void ClearUAVFloat( ITextureViewD3D12 *pTexView, const float* Color ); - void ClearUAVUint( ITextureViewD3D12 *pTexView, const UINT *Color ); + void ClearUAVFloat( D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle, D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, ID3D12Resource* pd3d12Resource, const float* Color ) + { + FlushResourceBarriers(); + m_pCommandList->ClearUnorderedAccessViewFloat(GpuHandle, CpuHandle, pd3d12Resource, Color, 0, nullptr); + } + + void ClearUAVUint( D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle, D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, ID3D12Resource* pd3d12Resource, const UINT* Color ) + { + FlushResourceBarriers(); + m_pCommandList->ClearUnorderedAccessViewUint(GpuHandle, CpuHandle, pd3d12Resource, Color, 0, nullptr); + } void CopyResource(ID3D12Resource *pDstRes, ID3D12Resource *pSrcRes) { @@ -174,8 +183,17 @@ protected: class GraphicsContext : public CommandContext { public: - void ClearRenderTarget( ITextureViewD3D12 *pRTV, const float *Color, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode ); - void ClearDepthStencil( ITextureViewD3D12 *pDSV, CLEAR_DEPTH_STENCIL_FLAGS ClearFlags, float Depth, UINT8 Stencil ); + void ClearRenderTarget( D3D12_CPU_DESCRIPTOR_HANDLE RTV, const float *Color ) + { + FlushResourceBarriers(); + m_pCommandList->ClearRenderTargetView(RTV, Color, 0, nullptr); + } + + void ClearDepthStencil( D3D12_CPU_DESCRIPTOR_HANDLE DSV, D3D12_CLEAR_FLAGS ClearFlags, float Depth, UINT8 Stencil ) + { + FlushResourceBarriers(); + m_pCommandList->ClearDepthStencilView(DSV, ClearFlags, Depth, Stencil, 0, nullptr); + } void SetRootSignature( ID3D12RootSignature *pRootSig ) { diff --git a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp index cfb4ba77..71859d23 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp @@ -91,157 +91,6 @@ ID3D12GraphicsCommandList* CommandContext::Close(CComPtr return m_pCommandList; } -void GraphicsContext::SetRenderTargets( UINT NumRTVs, ITextureViewD3D12** ppRTVs, ITextureViewD3D12* pDSV, SET_RENDER_TARGETS_FLAGS Flags ) -{ - D3D12_CPU_DESCRIPTOR_HANDLE RTVHandles[8]; // Do not waste time initializing array to zero - - for (UINT i = 0; i < NumRTVs; ++i) - { - auto *pRTV = ppRTVs[i]; - if( pRTV ) - { - auto* pTexture = ValidatedCast( pRTV->GetTexture() ); - if (Flags & SET_RENDER_TARGETS_FLAG_TRANSITION_COLOR) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_RENDER_TARGET)) - TransitionResource(pTexture, RESOURCE_STATE_RENDER_TARGET); - } -#ifdef DEVELOPMENT - else if (Flags & SET_RENDER_TARGETS_FLAG_VERIFY_STATES) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_RENDER_TARGET)) - { - LOG_ERROR_MESSAGE("Texture '", pTexture->GetDesc().Name, "' being set as render target at slot ", i, " is not transitioned to RESOURCE_STATE_RENDER_TARGET state. " - "Actual texture state: ", GetResourceStateString(pTexture->GetState()), ". " - "Use SET_RENDER_TARGETS_FLAG_TRANSITION_COLOR flag or explicitly transition the resource using IDeviceContext::TransitionResourceStates() method."); - } - } -#endif - - RTVHandles[i] = pRTV->GetCPUDescriptorHandle(); - VERIFY_EXPR(RTVHandles[i].ptr != 0); - } - } - - if (pDSV) - { - auto* pTexture = ValidatedCast( pDSV->GetTexture() ); - //if (bReadOnlyDepth) - //{ - // TransitionResource(*pTexture, D3D12_RESOURCE_STATE_DEPTH_READ); - // m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, &DSV->GetDSV_DepthReadOnly() ); - //} - //else - { - if (Flags & SET_RENDER_TARGETS_FLAG_TRANSITION_DEPTH) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_DEPTH_WRITE)) - TransitionResource(pTexture, RESOURCE_STATE_DEPTH_WRITE); - } -#ifdef DEVELOPMENT - else if (Flags & SET_RENDER_TARGETS_FLAG_VERIFY_STATES) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_DEPTH_WRITE)) - { - LOG_ERROR_MESSAGE("Texture '", pTexture->GetDesc().Name, "' being set as depth-stencil buffer is not transitioned to RESOURCE_STATE_DEPTH_WRITE state. " - "Actual texture state: ", GetResourceStateString(pTexture->GetState()), ". " - "Use SET_RENDER_TARGETS_FLAG_TRANSITION_DEPTH flag or explicitly transition the resource using IDeviceContext::TransitionResourceStates() method."); - } - - } -#endif - auto DSVHandle = pDSV->GetCPUDescriptorHandle(); - VERIFY_EXPR(DSVHandle.ptr != 0); - m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, &DSVHandle ); - } - } - else if(NumRTVs > 0) - { - m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, nullptr ); - } -} - -void CommandContext::ClearUAVFloat( ITextureViewD3D12* pTexView, const float* Color ) -{ - auto* pTexture = ValidatedCast( pTexView->GetTexture() ); - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) - TransitionResource(pTexture, RESOURCE_STATE_UNORDERED_ACCESS); - FlushResourceBarriers(); - // After binding a UAV, we can get a GPU handle that is required to clear it as a UAV (because it essentially runs - // a shader to set all of the values). - UNSUPPORTED("Not yet implemented"); - D3D12_GPU_DESCRIPTOR_HANDLE GpuVisibleHandle = {};//m_DynamicDescriptorHeap.UploadDirect(Target.GetUAV()); - m_pCommandList->ClearUnorderedAccessViewFloat(GpuVisibleHandle, pTexView->GetCPUDescriptorHandle(), pTexture->GetD3D12Resource(), Color, 0, nullptr); -} - -void CommandContext::ClearUAVUint( ITextureViewD3D12* pTexView, const UINT* Color ) -{ - auto* pTexture = ValidatedCast( pTexView->GetTexture() ); - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) - TransitionResource(pTexture, RESOURCE_STATE_UNORDERED_ACCESS); - - // After binding a UAV, we can get a GPU handle that is required to clear it as a UAV (because it essentially runs - // a shader to set all of the values). - UNSUPPORTED("Not yet implemented"); - D3D12_GPU_DESCRIPTOR_HANDLE GpuVisibleHandle = {};//m_DynamicDescriptorHeap.UploadDirect(Target.GetUAV()); - //CD3DX12_RECT ClearRect(0, 0, (LONG)Target.GetWidth(), (LONG)Target.GetHeight()); - FlushResourceBarriers(); - //TODO: My Nvidia card is not clearing UAVs with either Float or Uint variants. - m_pCommandList->ClearUnorderedAccessViewUint(GpuVisibleHandle, pTexView->GetCPUDescriptorHandle(), pTexture->GetD3D12Resource(), Color, 0, nullptr/*1, &ClearRect*/); -} - - -void GraphicsContext::ClearRenderTarget( ITextureViewD3D12* pRTV, const float* Color, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode ) -{ - auto *pTexture = ValidatedCast( pRTV->GetTexture() ); - if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_RENDER_TARGET)) - TransitionResource(pTexture, RESOURCE_STATE_RENDER_TARGET); - } -#ifdef DEVELOPMENT - else if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_RENDER_TARGET)) - { - LOG_ERROR_MESSAGE("Render target '", pTexture->GetDesc().Name, "' being cleared is not transitioned to RESOURCE_STATE_RENDER_TARGET state. " - "Actual texture state: ", GetResourceStateString(pTexture->GetState()), ". " - "Use RESOURCE_STATE_TRANSITION_MODE_TRANSITION mode or explicitly transition the resource using IDeviceContext::TransitionResourceStates() method."); - } - } -#endif - FlushResourceBarriers(); - m_pCommandList->ClearRenderTargetView(pRTV->GetCPUDescriptorHandle(), Color, 0, nullptr); -} - -void GraphicsContext::ClearDepthStencil( ITextureViewD3D12* pDSV, CLEAR_DEPTH_STENCIL_FLAGS ClearFlags, float Depth, UINT8 Stencil ) -{ - auto *pTexture = ValidatedCast( pDSV->GetTexture() ); - if (ClearFlags & CLEAR_DEPTH_STENCIL_TRANSITION_STATE_FLAG) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_DEPTH_WRITE)) - TransitionResource( pTexture, RESOURCE_STATE_DEPTH_WRITE); - } -#ifdef DEVELOPMENT - else if(ClearFlags & CLEAR_DEPTH_STENCIL_VERIFY_STATE_FLAG) - { - if (pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_DEPTH_WRITE)) - { - LOG_ERROR_MESSAGE("Depth-stencil buffer '", pTexture->GetDesc().Name, "' being cleared is not transitioned to RESOURCE_STATE_DEPTH_WRITE state. " - "Actual texture state: ", GetResourceStateString(pTexture->GetState()), ". " - "Use CLEAR_DEPTH_STENCIL_TRANSITION_STATE_FLAG flag or explicitly transition the resource using IDeviceContext::TransitionResourceStates() method."); - } - } -#endif - FlushResourceBarriers(); - - D3D12_CLEAR_FLAGS d3d12ClearFlags = (D3D12_CLEAR_FLAGS)0; - if( ClearFlags & CLEAR_DEPTH_FLAG ) d3d12ClearFlags |= D3D12_CLEAR_FLAG_DEPTH; - if( ClearFlags & CLEAR_STENCIL_FLAG ) d3d12ClearFlags |= D3D12_CLEAR_FLAG_STENCIL; - m_pCommandList->ClearDepthStencilView(pDSV->GetCPUDescriptorHandle(), d3d12ClearFlags, Depth, Stencil, 0, nullptr); -} - - void CommandContext::TransitionResource(ITextureD3D12* pTexture, RESOURCE_STATE NewState) { VERIFY_EXPR( pTexture != nullptr ); diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 60bf0633..d0fed52d 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -559,12 +559,12 @@ namespace Diligent void DeviceContextD3D12Impl::ClearDepthStencil( ITextureView* pView, CLEAR_DEPTH_STENCIL_FLAGS ClearFlags, float fDepth, Uint8 Stencil ) { - ITextureViewD3D12 *pDSVD3D12 = nullptr; + ITextureViewD3D12* pViewD3D12 = nullptr; if( pView != nullptr ) { - pDSVD3D12 = ValidatedCast(pView); + pViewD3D12 = ValidatedCast(pView); #ifdef _DEBUG - const auto& ViewDesc = pDSVD3D12->GetDesc(); + const auto& ViewDesc = pViewD3D12->GetDesc(); VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL, "Incorrect view type: depth stencil is expected" ); #endif } @@ -572,7 +572,7 @@ namespace Diligent { if (m_pSwapChain) { - pDSVD3D12 = ValidatedCast(m_pSwapChain.RawPtr()->GetDepthBufferDSV()); + pViewD3D12 = ValidatedCast(m_pSwapChain.RawPtr()->GetDepthBufferDSV()); } else { @@ -580,28 +580,43 @@ namespace Diligent return; } } + + auto* pTextureD3D12 = ValidatedCast( pViewD3D12->GetTexture() ); + auto& CmdCtx = GetCmdContext(); + auto TransitionMode = + (ClearFlags & CLEAR_DEPTH_STENCIL_TRANSITION_STATE_FLAG) ? + RESOURCE_STATE_TRANSITION_MODE_TRANSITION : + ((ClearFlags & CLEAR_DEPTH_STENCIL_VERIFY_STATE_FLAG) ? + RESOURCE_STATE_TRANSITION_MODE_VERIFY : + RESOURCE_STATE_TRANSITION_MODE_NONE); + TransitionOrVerifyTextureState(CmdCtx, *pTextureD3D12, TransitionMode, RESOURCE_STATE_DEPTH_WRITE, "Clearing depth-stencil buffer (DeviceContextD3D12Impl::ClearDepthStencil)"); + + D3D12_CLEAR_FLAGS d3d12ClearFlags = (D3D12_CLEAR_FLAGS)0; + if( ClearFlags & CLEAR_DEPTH_FLAG ) d3d12ClearFlags |= D3D12_CLEAR_FLAG_DEPTH; + if( ClearFlags & CLEAR_STENCIL_FLAG ) d3d12ClearFlags |= D3D12_CLEAR_FLAG_STENCIL; + // The full extent of the resource view is always cleared. // Viewport and scissor settings are not applied?? - GetCmdContext().AsGraphicsContext().ClearDepthStencil( pDSVD3D12, ClearFlags, fDepth, Stencil ); + GetCmdContext().AsGraphicsContext().ClearDepthStencil( pViewD3D12->GetCPUDescriptorHandle(), d3d12ClearFlags, fDepth, Stencil ); ++m_State.NumCommands; } void DeviceContextD3D12Impl::ClearRenderTarget( ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode ) { - ITextureViewD3D12 *pd3d12RTV = nullptr; + ITextureViewD3D12* pViewD3D12 = nullptr; if( pView != nullptr ) { #ifdef _DEBUG const auto& ViewDesc = pView->GetDesc(); VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET, "Incorrect view type: render target is expected" ); #endif - pd3d12RTV = ValidatedCast(pView); + pViewD3D12 = ValidatedCast(pView); } else { if (m_pSwapChain) { - pd3d12RTV = ValidatedCast(m_pSwapChain.RawPtr()->GetCurrentBackBufferRTV()); + pViewD3D12 = ValidatedCast(m_pSwapChain.RawPtr()->GetCurrentBackBufferRTV()); } else { @@ -614,9 +629,13 @@ namespace Diligent if( RGBA == nullptr ) RGBA = Zero; + auto* pTextureD3D12 = ValidatedCast( pViewD3D12->GetTexture() ); + auto& CmdCtx = GetCmdContext(); + TransitionOrVerifyTextureState(CmdCtx, *pTextureD3D12, StateTransitionMode, RESOURCE_STATE_RENDER_TARGET, "Clearing render target (DeviceContextD3D12Impl::ClearRenderTarget)"); + // The full extent of the resource view is always cleared. // Viewport and scissor settings are not applied?? - GetCmdContext().AsGraphicsContext().ClearRenderTarget( pd3d12RTV, RGBA, StateTransitionMode ); + CmdCtx.AsGraphicsContext().ClearRenderTarget( pViewD3D12->GetCPUDescriptorHandle(), RGBA ); ++m_State.NumCommands; } @@ -814,7 +833,6 @@ namespace Diligent } } - void DeviceContextD3D12Impl::CommitRenderTargets(SET_RENDER_TARGETS_FLAGS Flags) { const Uint32 MaxD3D12RTs = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; @@ -822,8 +840,8 @@ namespace Diligent VERIFY( NumRenderTargets <= MaxD3D12RTs, "D3D12 only allows 8 simultaneous render targets" ); NumRenderTargets = std::min( MaxD3D12RTs, NumRenderTargets ); - ITextureViewD3D12 *ppRTVs[MaxD3D12RTs]; // Do not initialize with zeroes! - ITextureViewD3D12 *pDSV = nullptr; + ITextureViewD3D12* ppRTVs[MaxD3D12RTs]; // Do not initialize with zeroes! + ITextureViewD3D12* pDSV = nullptr; if( m_IsDefaultFramebufferBound ) { if (m_pSwapChain) @@ -845,7 +863,50 @@ namespace Diligent ppRTVs[rt] = m_pBoundRenderTargets[rt].RawPtr(); pDSV = m_pBoundDepthStencil.RawPtr(); } - GetCmdContext().AsGraphicsContext().SetRenderTargets(NumRenderTargets, ppRTVs, pDSV, Flags); + + auto& CmdCtx = GetCmdContext(); + D3D12_CPU_DESCRIPTOR_HANDLE RTVHandles[8]; // Do not waste time initializing array to zero + D3D12_CPU_DESCRIPTOR_HANDLE DSVHandle = {}; + for (UINT i = 0; i < NumRenderTargets; ++i) + { + if( auto* pRTV = ppRTVs[i] ) + { + auto* pTexture = ValidatedCast( pRTV->GetTexture() ); + auto RTTransitionMode = (Flags & SET_RENDER_TARGETS_FLAG_TRANSITION_COLOR) ? + RESOURCE_STATE_TRANSITION_MODE_TRANSITION : + ((Flags & SET_RENDER_TARGETS_FLAG_VERIFY_STATES) ? + RESOURCE_STATE_TRANSITION_MODE_VERIFY : + RESOURCE_STATE_TRANSITION_MODE_NONE); + TransitionOrVerifyTextureState(CmdCtx, *pTexture, RTTransitionMode, RESOURCE_STATE_RENDER_TARGET, "Setting render targets (DeviceContextD3D12Impl::CommitRenderTargets)"); + RTVHandles[i] = pRTV->GetCPUDescriptorHandle(); + VERIFY_EXPR(RTVHandles[i].ptr != 0); + } + } + + if (pDSV) + { + auto* pTexture = ValidatedCast( pDSV->GetTexture() ); + //if (bReadOnlyDepth) + //{ + // TransitionResource(*pTexture, D3D12_RESOURCE_STATE_DEPTH_READ); + // m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, &DSV->GetDSV_DepthReadOnly() ); + //} + //else + { + auto DepthTransitionMode = (Flags & SET_RENDER_TARGETS_FLAG_TRANSITION_DEPTH) ? + RESOURCE_STATE_TRANSITION_MODE_TRANSITION : + ((Flags & SET_RENDER_TARGETS_FLAG_VERIFY_STATES) ? + RESOURCE_STATE_TRANSITION_MODE_VERIFY : + RESOURCE_STATE_TRANSITION_MODE_NONE); + TransitionOrVerifyTextureState(CmdCtx, *pTexture, DepthTransitionMode, RESOURCE_STATE_DEPTH_WRITE, "Setting depth-stencil buffer (DeviceContextD3D12Impl::CommitRenderTargets)"); + DSVHandle = pDSV->GetCPUDescriptorHandle(); + VERIFY_EXPR(DSVHandle.ptr != 0); + } + } + + VERIFY_EXPR(NumRenderTargets > 0 || DSVHandle.ptr != 0); + // No need to flush resource barriers as this is a CPU-side command + CmdCtx.AsGraphicsContext().GetCommandList()->OMSetRenderTargets( NumRenderTargets, RTVHandles, FALSE, DSVHandle.ptr != 0 ? &DSVHandle : nullptr ); } void DeviceContextD3D12Impl::SetRenderTargets( Uint32 NumRenderTargets, ITextureView *ppRenderTargets[], ITextureView *pDepthStencil, SET_RENDER_TARGETS_FLAGS Flags ) -- cgit v1.2.3