From 3d9f381db2749ec19e5f49b9d095da95445cb806 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Tue, 20 Nov 2018 19:38:52 -0800 Subject: Implemented explicit state transitions in D3D11 backend (closed https://github.com/DiligentGraphics/DiligentCore/issues/6) --- .../interface/GraphicsAccessories.h | 2 + .../src/GraphicsAccessories.cpp | 57 ++++++ .../GraphicsEngine/include/DeviceContextBase.h | 46 +++++ .../GraphicsEngineD3D11/include/BufferD3D11Impl.h | 19 +- .../GraphicsEngineD3D11/include/TextureBaseD3D11.h | 18 +- .../GraphicsEngineD3D11/src/BufferD3D11Impl.cpp | 2 + .../src/DeviceContextD3D11Impl.cpp | 217 +++++++++++++++------ .../GraphicsEngineD3D11/src/TextureBaseD3D11.cpp | 1 + .../GraphicsEngineD3D12/src/CommandContext.cpp | 24 +-- .../src/DeviceContextD3D12Impl.cpp | 5 + .../src/DeviceContextVkImpl.cpp | 44 ++--- 11 files changed, 302 insertions(+), 133 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsAccessories/interface/GraphicsAccessories.h b/Graphics/GraphicsAccessories/interface/GraphicsAccessories.h index 89641c1c..36a0b0fa 100644 --- a/Graphics/GraphicsAccessories/interface/GraphicsAccessories.h +++ b/Graphics/GraphicsAccessories/interface/GraphicsAccessories.h @@ -282,4 +282,6 @@ inline bool IsAnisotropicFilter(FILTER_TYPE FilterType) FilterType == FILTER_TYPE_MAXIMUM_ANISOTROPIC; } +bool VerifyResourceStates(RESOURCE_STATE State, bool IsTexture); + } diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index 3a51a2c2..0f316e5c 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -815,6 +815,7 @@ String GetResourceStateString( RESOURCE_STATE State ) auto lsb = State & ~(State-1); const auto* StateFlagString = GetResourceStateFlagString(static_cast(lsb)); str.append(StateFlagString); + State = static_cast(State & ~lsb); } return str; } @@ -841,4 +842,60 @@ Uint32 ComputeMipLevelsCount( Uint32 Width, Uint32 Height, Uint32 Depth ) return ComputeMipLevelsCount( std::max(std::max( Width, Height ), Depth) ); } +bool VerifyResourceStates(RESOURCE_STATE State, bool IsTexture) +{ + static_assert(RESOURCE_STATE_MAX_BIT == 0x8000, "Please update this function to handle the new resource state"); + +#define VERIFY_EXCLUSIVE_STATE(ExclusiveState)\ +if ( (State & ExclusiveState) != 0 && (State & ~ExclusiveState) != 0 )\ +{\ + LOG_ERROR_MESSAGE("State ", GetResourceStateString(State), " is invalid: " #ExclusiveState " can't be combined with any other state");\ + return false;\ +} + + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_UNDEFINED); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_UNORDERED_ACCESS); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_RENDER_TARGET); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_DEPTH_WRITE); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_COPY_DEST); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_RESOLVE_DEST); + VERIFY_EXCLUSIVE_STATE(RESOURCE_STATE_PRESENT); +#undef VERIFY_EXCLUSIVE_STATE + + if (IsTexture) + { + if (State & + (RESOURCE_STATE_VERTEX_BUFFER | + RESOURCE_STATE_CONSTANT_BUFFER | + RESOURCE_STATE_INDEX_BUFFER | + RESOURCE_STATE_STREAM_OUT | + RESOURCE_STATE_INDIRECT_ARGUMENT)) + { + LOG_ERROR_MESSAGE("State ", GetResourceStateString(State), " is invalid: states RESOURCE_STATE_VERTEX_BUFFER, " + "RESOURCE_STATE_CONSTANT_BUFFER, RESOURCE_STATE_INDEX_BUFFER, RESOURCE_STATE_STREAM_OUT, " + "RESOURCE_STATE_INDIRECT_ARGUMENT are not applicable to a texture"); + return false; + } + } + else + { + if (State & + (RESOURCE_STATE_RENDER_TARGET | + RESOURCE_STATE_DEPTH_WRITE | + RESOURCE_STATE_DEPTH_READ | + RESOURCE_STATE_RESOLVE_SOURCE | + RESOURCE_STATE_RESOLVE_DEST | + RESOURCE_STATE_PRESENT)) + { + LOG_ERROR_MESSAGE("State ", GetResourceStateString(State), " is invalid: states RESOURCE_STATE_RENDER_TARGET, " + "RESOURCE_STATE_DEPTH_WRITE, RESOURCE_STATE_DEPTH_READ, RESOURCE_STATE_RESOLVE_SOURCE, " + "RESOURCE_STATE_RESOLVE_DEST, RESOURCE_STATE_PRESENT are not applicable to a buffer"); + return false; + + } + } + + return true; +} + } diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.h b/Graphics/GraphicsEngine/include/DeviceContextBase.h index b7851dae..23861605 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.h +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.h @@ -146,6 +146,7 @@ protected: #ifdef DEVELOPMENT bool DvpVerifyDrawArguments(const DrawAttribs& drawAttribs); bool DvpVerifyDispatchArguments(const DispatchComputeAttribs &DispatchAttrs); + void DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier); #endif /// Strong reference to the device. @@ -693,6 +694,51 @@ inline bool DeviceContextBase +void DeviceContextBase :: DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) +{ + DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer members of StateTransitionDesc must not be null"); + DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); + if (Barrier.pTexture) + { + const auto& TexDesc = Barrier.pTexture->GetDesc(); + + DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, true), "Invlaid new state specified for texture '", TexDesc.Name, "'"); + auto OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : Barrier.pTexture->GetState(); + DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of texture '", TexDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + DEV_CHECK_ERR(VerifyResourceStates(OldState, true), "Invlaid old state specified for texture '", TexDesc.Name, "'"); + + DEV_CHECK_ERR(Barrier.FirstMipLevel < TexDesc.MipLevels, "First mip level (", Barrier.FirstMipLevel, ") specified by the barrier is " + "out of range. Texture '", TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)"); + DEV_CHECK_ERR(Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels || Barrier.FirstMipLevel + Barrier.MipLevelsCount < TexDesc.MipLevels, + "Mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel+Barrier.MipLevelsCount-1, " " + "specified by the barrier is out of range. Texture '", TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)"); + + DEV_CHECK_ERR(Barrier.FirstArraySlice < TexDesc.ArraySize, "First array slice (", Barrier.FirstArraySlice, ") specified by the barrier is " + "out of range. Array size of texture '", TexDesc.Name, "' is ", TexDesc.ArraySize); + DEV_CHECK_ERR(Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices || Barrier.FirstArraySlice + Barrier.ArraySliceCount < TexDesc.ArraySize, + "Array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice+Barrier.ArraySliceCount-1, " " + "specified by the barrier is out of range. Array size of texture '", TexDesc.Name, "' is ", TexDesc.ArraySize); + + auto DevType = m_pDevice->GetDeviceCaps().DevType; + if (DevType != DeviceType::D3D12 && DevType != DeviceType::Vulkan) + { + DEV_CHECK_ERR(Barrier.FirstMipLevel == 0 && (Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels || Barrier.MipLevelsCount == TexDesc.MipLevels), + "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); + DEV_CHECK_ERR(Barrier.FirstArraySlice == 0 && (Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices || Barrier.ArraySliceCount == TexDesc.ArraySize), + "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device"); + } + } + else + { + const auto& BuffDesc = Barrier.pBuffer->GetDesc(); + DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, false), "Invlaid new state specified for buffer '", BuffDesc.Name, "'"); + auto OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : Barrier.pBuffer->GetState(); + DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of buffer '", BuffDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier"); + DEV_CHECK_ERR(VerifyResourceStates(OldState, false), "Invlaid old state specified for buffer '", BuffDesc.Name, "'"); + } +} + #endif diff --git a/Graphics/GraphicsEngineD3D11/include/BufferD3D11Impl.h b/Graphics/GraphicsEngineD3D11/include/BufferD3D11Impl.h index 80fed967..c0d47666 100644 --- a/Graphics/GraphicsEngineD3D11/include/BufferD3D11Impl.h +++ b/Graphics/GraphicsEngineD3D11/include/BufferD3D11Impl.h @@ -37,17 +37,6 @@ namespace Diligent class FixedBlockMemoryAllocator; -enum class D3D11BufferState -{ - Undefined = 0x00, - ShaderResource = 0x01, - ConstantBuffer = 0x02, - VertexBuffer = 0x04, - IndexBuffer = 0x08, - UnorderedAccess = 0x10, - AnyInput = ShaderResource | ConstantBuffer | VertexBuffer | IndexBuffer -}; - /// Implementation of the Diligent::IBufferD3D11 interface class BufferD3D11Impl final : public BufferBase { @@ -79,10 +68,8 @@ public: virtual void* GetNativeHandle()override final { return GetD3D11Buffer(); } - void ResetState(D3D11BufferState State){m_State = static_cast(State);} - void AddState(D3D11BufferState State) {m_State |= static_cast(State);} - void ClearState(D3D11BufferState State){m_State &= ~static_cast(State);} - bool CheckState(D3D11BufferState State){return (m_State & static_cast(State)) ? true : false;} + void AddState (RESOURCE_STATE State){m_State = static_cast(m_State | State);} + void ClearState(RESOURCE_STATE State){m_State = static_cast(m_State & ~static_cast(State));} private: virtual void CreateViewInternal( const struct BufferViewDesc &ViewDesc, IBufferView **ppView, bool bIsDefaultView )override; @@ -92,8 +79,6 @@ private: friend class DeviceContextD3D11Impl; CComPtr m_pd3d11Buffer; ///< D3D11 buffer object - - Uint32 m_State = static_cast(D3D11BufferState::Undefined); }; } diff --git a/Graphics/GraphicsEngineD3D11/include/TextureBaseD3D11.h b/Graphics/GraphicsEngineD3D11/include/TextureBaseD3D11.h index 662220a4..f17bba70 100644 --- a/Graphics/GraphicsEngineD3D11/include/TextureBaseD3D11.h +++ b/Graphics/GraphicsEngineD3D11/include/TextureBaseD3D11.h @@ -37,16 +37,6 @@ namespace Diligent class FixedBlockMemoryAllocator; -enum class D3D11TextureState -{ - Undefined = 0x0, - ShaderResource = 0x1, - RenderTarget = 0x2, - DepthStencil = 0x4, - UnorderedAccess = 0x8, - Output = RenderTarget | DepthStencil | UnorderedAccess -}; - /// Base implementation of the Diligent::ITextureD3D11 interface class TextureBaseD3D11 : public TextureBase { @@ -90,10 +80,8 @@ public: Uint32 DstY, Uint32 DstZ); - void ResetState(D3D11TextureState State){m_State = static_cast(State);} - void AddState(D3D11TextureState State) {m_State |= static_cast(State);} - void ClearState(D3D11TextureState State){m_State &= ~static_cast(State);} - bool CheckState(D3D11TextureState State){return (m_State & static_cast(State)) ? true : false;} + void AddState (RESOURCE_STATE State){m_State = static_cast(m_State | State);} + void ClearState(RESOURCE_STATE State){m_State = static_cast(m_State & ~static_cast(State));} protected: void CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )override final; @@ -108,8 +96,6 @@ protected: friend class RenderDeviceD3D11Impl; /// D3D11 texture CComPtr m_pd3d11Texture; - - Uint32 m_State = static_cast(D3D11TextureState::Undefined); }; } diff --git a/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp index 28940739..d0888937 100644 --- a/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/BufferD3D11Impl.cpp @@ -103,6 +103,8 @@ BufferD3D11Impl :: BufferD3D11Impl(IReferenceCounters* pRefCounters, auto hr = m_pd3d11Buffer->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(strlen(m_Desc.Name)), m_Desc.Name); DEV_CHECK_ERR(SUCCEEDED(hr), "Failed to set buffer name"); } + + SetState(RESOURCE_STATE_UNDEFINED); } static BufferDesc BuffDescFromD3D11Buffer(ID3D11Buffer *pd3d11Buffer, BufferDesc BuffDesc) diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 9b586f70..dee55fc8 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -244,38 +244,38 @@ namespace Diligent // individually, or not rely on the state and check current context bindings if(TransitionResources) { - if ( auto* pTexture = const_cast(UAVRes.pTexture) ) + if ( auto* pTexture = ValidatedCast(UAVRes.pTexture) ) { - if( !pTexture->CheckState(D3D11TextureState::UnorderedAccess) ) + if( pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { - if( pTexture->CheckState(D3D11TextureState::ShaderResource) ) + if( pTexture->CheckState(RESOURCE_STATE_SHADER_RESOURCE) ) UnbindTextureFromInput( pTexture, UAVRes.pd3d11Resource ); - pTexture->ResetState(D3D11TextureState::UnorderedAccess); + pTexture->SetState(RESOURCE_STATE_UNORDERED_ACCESS); } } - else if( auto* pBuffer = const_cast(UAVRes.pBuffer) ) + else if( auto* pBuffer = ValidatedCast(UAVRes.pBuffer) ) { - if( !pBuffer->CheckState(D3D11BufferState::UnorderedAccess) ) + if( pBuffer->IsInKnownState() && !pBuffer->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { - if( pBuffer->CheckState(D3D11BufferState::AnyInput) ) + if( (pBuffer->GetState() & RESOURCE_STATE_GENERIC_READ) != 0 ) UnbindBufferFromInput( pBuffer, UAVRes.pd3d11Resource ); - pBuffer->ResetState(D3D11BufferState::UnorderedAccess); + pBuffer->SetState(RESOURCE_STATE_UNORDERED_ACCESS); } } } #ifdef DEVELOPMENT else { - if ( auto* pTexture = const_cast(UAVRes.pTexture) ) + if ( auto* pTexture = ValidatedCast(UAVRes.pTexture) ) { - if( !pTexture->CheckState(D3D11TextureState::UnorderedAccess) ) + if( pTexture->IsInKnownState () && !pTexture->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { LOG_ERROR_MESSAGE("Texture \"", pTexture->GetDesc().Name, "\" has not been transitioned to Unordered Access state. Did you forget to call TransitionResources()?"); } } - else if( auto* pBuffer = const_cast(UAVRes.pBuffer) ) + else if( auto* pBuffer = ValidatedCast(UAVRes.pBuffer) ) { - if( !pBuffer->CheckState(D3D11BufferState::UnorderedAccess) ) + if( pBuffer->IsInKnownState() && !pBuffer->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { LOG_ERROR_MESSAGE("Buffer \"", pBuffer->GetDesc().Name, "\" has not been transitioned to Unordered Access state. Did you forget to call TransitionResources()?"); } @@ -384,23 +384,23 @@ namespace Diligent if(TransitionResources) { auto &CB = CachedCBs[cb]; - if( auto* pBuff = const_cast(CB.pBuff.RawPtr()) ) + if( auto* pBuff = CB.pBuff.RawPtr() ) { // WARNING! This code is not thread-safe. If several threads change // the buffer state, the results will be undefined. // The solution may be to keep track of the state for each thread // individually, or not rely on the state and check current context bindings - if(!pBuff->CheckState(D3D11BufferState::ConstantBuffer)) + if(pBuff->IsInKnownState() && !pBuff->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) { - if( pBuff->CheckState(D3D11BufferState::UnorderedAccess) ) + if( pBuff->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { // Even though we have unbound resources from UAV, we only checked shader // stages active in current PSO, so we still may need to unbind the resource // from UAV (for instance, unbind resource from CS UAV when running draw command). UnbindResourceFromUAV( pBuff, d3d11CBs[cb] ); - pBuff->ClearState(D3D11BufferState::UnorderedAccess); + pBuff->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); } - pBuff->AddState(D3D11BufferState::ConstantBuffer); + pBuff->AddState(RESOURCE_STATE_CONSTANT_BUFFER); } } } @@ -409,9 +409,9 @@ namespace Diligent { VERIFY_EXPR(CommitResources); auto &CB = CachedCBs[cb]; - if( auto* pBuff = const_cast(CB.pBuff.RawPtr()) ) + if( auto* pBuff = CB.pBuff.RawPtr() ) { - if (!pBuff->CheckState(D3D11BufferState::ConstantBuffer)) + if (pBuff->IsInKnownState() && !pBuff->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) { LOG_ERROR_MESSAGE("Buffer \"", pBuff->GetDesc().Name, "\" has not been transitioned to Constant Buffer state. Did you forget to call TransitionResources()?"); } @@ -472,33 +472,34 @@ namespace Diligent { if (auto* pTexture = const_cast(SRVRes.pTexture)) { - if( !pTexture->CheckState(D3D11TextureState::ShaderResource) ) + if( pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_SHADER_RESOURCE) ) { - if( pTexture->CheckState(D3D11TextureState::UnorderedAccess) ) + if( pTexture->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { // Even though we have unbound resources from UAV, we only checked shader // stages active in current PSO, so we still may need to unbind the resource // from UAV (for instance, unbind resource from CS UAV when running draw command). UnbindResourceFromUAV(pTexture, SRVRes.pd3d11Resource); - pTexture->ClearState(D3D11TextureState::UnorderedAccess); + pTexture->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); } - if( pTexture->CheckState(D3D11TextureState::RenderTarget) ) + // Clearing RESOURCE_STATE_UNORDERED_ACCESS flag may result in RESOURCE_STATE_UNKNOWN state + if( pTexture->IsInKnownState() && pTexture->CheckState(RESOURCE_STATE_RENDER_TARGET) ) UnbindTextureFromRenderTarget(pTexture); - if( pTexture->CheckState(D3D11TextureState::DepthStencil) ) + if( pTexture->IsInKnownState() && pTexture->CheckState(RESOURCE_STATE_DEPTH_WRITE) ) UnbindTextureFromDepthStencil(pTexture); - pTexture->ResetState(D3D11TextureState::ShaderResource); + pTexture->SetState(RESOURCE_STATE_SHADER_RESOURCE); } } - else if(auto* pBuffer = const_cast(SRVRes.pBuffer)) + else if(auto* pBuffer = ValidatedCast(SRVRes.pBuffer)) { - if( !pBuffer->CheckState(D3D11BufferState::ShaderResource) ) + if( pBuffer->IsInKnownState() && !pBuffer->CheckState(RESOURCE_STATE_SHADER_RESOURCE) ) { - if( pBuffer->CheckState(D3D11BufferState::UnorderedAccess) ) + if( pBuffer->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { UnbindResourceFromUAV( pBuffer, SRVRes.pd3d11Resource ); - pBuffer->ClearState(D3D11BufferState::UnorderedAccess); + pBuffer->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); } - pBuffer->AddState(D3D11BufferState::ShaderResource); + pBuffer->AddState(RESOURCE_STATE_SHADER_RESOURCE); } } } @@ -506,16 +507,16 @@ namespace Diligent else { VERIFY_EXPR(CommitResources); - if (auto* pTexture = const_cast(SRVRes.pTexture)) + if (auto* pTexture = ValidatedCast(SRVRes.pTexture)) { - if( !pTexture->CheckState(D3D11TextureState::ShaderResource) ) + if( pTexture->IsInKnownState() && !pTexture->CheckState(RESOURCE_STATE_SHADER_RESOURCE) ) { LOG_ERROR_MESSAGE("Texture \"", pTexture->GetDesc().Name, "\" has not been transitioned to Shader Resource state. Did you forget to call TransitionResources()?"); } } - else if(auto* pBuffer = const_cast(SRVRes.pBuffer)) + else if(auto* pBuffer = ValidatedCast(SRVRes.pBuffer)) { - if( !pBuffer->CheckState(D3D11BufferState::ShaderResource) ) + if( pBuffer->IsInKnownState() && !pBuffer->CheckState(RESOURCE_STATE_SHADER_RESOURCE) ) { LOG_ERROR_MESSAGE("Texture \"", pBuffer->GetDesc().Name, "\" has not been transitioned to Shader Resource state. Did you forget to call TransitionResources()?"); } @@ -661,10 +662,10 @@ namespace Diligent } BufferD3D11Impl* pBuffD3D11 = m_pIndexBuffer.RawPtr(); - if( pBuffD3D11->CheckState( D3D11BufferState::UnorderedAccess ) ) + if( pBuffD3D11->IsInKnownState() && pBuffD3D11->CheckState(RESOURCE_STATE_UNORDERED_ACCESS) ) { UnbindResourceFromUAV(pBuffD3D11, pBuffD3D11->m_pd3d11Buffer); - pBuffD3D11->ClearState( D3D11BufferState::UnorderedAccess ); + pBuffD3D11->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); } if( m_CommittedD3D11IndexBuffer != pBuffD3D11->m_pd3d11Buffer || @@ -688,7 +689,7 @@ namespace Diligent m_pd3d11DeviceContext->IASetIndexBuffer( pBuffD3D11->m_pd3d11Buffer, D3D11IndexFmt, m_IndexDataStartOffset ); } - pBuffD3D11->AddState(D3D11BufferState::IndexBuffer); + pBuffD3D11->AddState(RESOURCE_STATE_INDEX_BUFFER); m_bCommittedD3D11IBUpToDate = true; } @@ -708,10 +709,10 @@ namespace Diligent auto Stride = Strides[Slot]; auto Offset = CurrStream.Offset; - if(pBuffD3D11Impl != nullptr && pBuffD3D11Impl->CheckState( D3D11BufferState::UnorderedAccess )) + if(pBuffD3D11Impl != nullptr && pBuffD3D11Impl->IsInKnownState() && pBuffD3D11Impl->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) { UnbindResourceFromUAV(pBuffD3D11Impl, pd3d11Buffer); - pBuffD3D11Impl->ClearState( D3D11BufferState::UnorderedAccess ); + pBuffD3D11Impl->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); } // It is safe to perform raw pointer check because device context keeps @@ -727,7 +728,7 @@ namespace Diligent m_CommittedD3D11VBOffsets[Slot] = Offset; if (pBuffD3D11Impl) - pBuffD3D11Impl->AddState( D3D11BufferState::VertexBuffer ); + pBuffD3D11Impl->AddState(RESOURCE_STATE_VERTEX_BUFFER); } } @@ -1147,21 +1148,21 @@ namespace Diligent if( !pTexture )return; UnbindResourceView( m_CommittedD3D11SRVs, m_CommittedD3D11SRVResources, m_NumCommittedSRVs, pd3d11Resource, SetSRVMethods ); - pTexture->ClearState(D3D11TextureState::ShaderResource); + pTexture->ClearState(RESOURCE_STATE_SHADER_RESOURCE); } void DeviceContextD3D11Impl::UnbindBufferFromInput( BufferD3D11Impl* pBuffer, ID3D11Resource* pd3d11Buffer ) { VERIFY( pBuffer, "Null buffer provided" ); - if( !pBuffer )return; - - if( pBuffer->CheckState(D3D11BufferState::ShaderResource) ) + if( !pBuffer || !pBuffer->IsInKnownState())return; + + if( pBuffer->CheckState(RESOURCE_STATE_SHADER_RESOURCE) ) { UnbindResourceView( m_CommittedD3D11SRVs, m_CommittedD3D11SRVResources, m_NumCommittedSRVs, pd3d11Buffer, SetSRVMethods ); - pBuffer->ClearState( D3D11BufferState::ShaderResource ); + pBuffer->ClearState(RESOURCE_STATE_SHADER_RESOURCE); } - if( pBuffer->CheckState(D3D11BufferState::IndexBuffer) ) + if( pBuffer->IsInKnownState() && pBuffer->CheckState(RESOURCE_STATE_INDEX_BUFFER) ) { auto pd3d11IndBuffer = ValidatedCast( pBuffer )->GetD3D11Buffer(); if( pd3d11IndBuffer == m_CommittedD3D11IndexBuffer ) @@ -1178,10 +1179,10 @@ namespace Diligent { dbgVerifyCommittedIndexBuffer(); } - pBuffer->ClearState( D3D11BufferState::IndexBuffer ); + pBuffer->ClearState(RESOURCE_STATE_INDEX_BUFFER); } - if( pBuffer->CheckState( D3D11BufferState::VertexBuffer ) ) + if( pBuffer->IsInKnownState() && pBuffer->CheckState(RESOURCE_STATE_VERTEX_BUFFER) ) { auto pd3d11VB = ValidatedCast( pBuffer )->GetD3D11Buffer(); for( Uint32 Slot = 0; Slot < m_NumCommittedD3D11VBs; ++Slot ) @@ -1204,10 +1205,10 @@ namespace Diligent { dbgVerifyCommittedVertexBuffers(); } - pBuffer->ClearState( D3D11BufferState::VertexBuffer ); + pBuffer->ClearState(RESOURCE_STATE_VERTEX_BUFFER); } - if( pBuffer->CheckState( D3D11BufferState::ConstantBuffer ) ) + if( pBuffer->IsInKnownState() && pBuffer->CheckState(RESOURCE_STATE_CONSTANT_BUFFER) ) { for( Int32 ShaderTypeInd = 0; ShaderTypeInd < NumShaderTypes; ++ShaderTypeInd ) { @@ -1228,7 +1229,7 @@ namespace Diligent { dbgVerifyCommittedCBs(); } - pBuffer->ClearState( D3D11BufferState::ConstantBuffer ); + pBuffer->ClearState(RESOURCE_STATE_CONSTANT_BUFFER); } } @@ -1266,7 +1267,7 @@ namespace Diligent CommitRenderTargets(); } - pTexture->ClearState(D3D11TextureState::RenderTarget); + pTexture->ClearState(RESOURCE_STATE_RENDER_TARGET); } void DeviceContextD3D11Impl::UnbindTextureFromDepthStencil(TextureBaseD3D11* pTexD3D11) @@ -1279,7 +1280,7 @@ namespace Diligent m_pBoundDepthStencil.Release(); CommitRenderTargets(); } - pTexD3D11->ClearState(D3D11TextureState::DepthStencil); + pTexD3D11->ClearState(RESOURCE_STATE_DEPTH_WRITE); } void DeviceContextD3D11Impl::ResetRenderTargets() @@ -1297,13 +1298,15 @@ namespace Diligent { auto* pTex = ValidatedCast(ppRenderTargets[RT]->GetTexture()); UnbindTextureFromInput( pTex, pTex->GetD3D11Texture() ); - pTex->ResetState(D3D11TextureState::RenderTarget); + if (pTex->IsInKnownState()) + pTex->SetState(RESOURCE_STATE_RENDER_TARGET); } if( pDepthStencil ) { auto* pTex = ValidatedCast(pDepthStencil->GetTexture()); UnbindTextureFromInput( pTex, pTex->GetD3D11Texture() ); - pTex->ResetState(D3D11TextureState::DepthStencil); + if (pTex->IsInKnownState()) + pTex->SetState(RESOURCE_STATE_DEPTH_WRITE); } CommitRenderTargets(); @@ -1569,7 +1572,111 @@ namespace Diligent void DeviceContextD3D11Impl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { + for(Uint32 i=0; i < BarrierCount; ++i) + { + const auto& Barrier = pResourceBarriers[i]; +#ifdef DEVELOPMENT + DvpVerifyStateTransitionDesc(Barrier); +#endif + DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer must not be null"); + DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); + + if (Barrier.pTexture) + { + auto* pTextureD3D11Impl = ValidatedCast(Barrier.pTexture); + auto OldState = Barrier.OldState; + if (OldState == RESOURCE_STATE_UNKNOWN) + { + if (pTextureD3D11Impl->IsInKnownState()) + { + OldState = pTextureD3D11Impl->GetState(); + } + else + { + LOG_ERROR_MESSAGE("Failed to transition the state of texture '", pTextureD3D11Impl->GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); + continue; + } + } + else + { + if (pTextureD3D11Impl->IsInKnownState() && pTextureD3D11Impl->GetState() != OldState) + { + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(pTextureD3D11Impl->GetState()), " of texture '", + pTextureD3D11Impl->GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); + } + } + + if ((Barrier.NewState & RESOURCE_STATE_UNORDERED_ACCESS) != 0) + { + DEV_CHECK_ERR((Barrier.NewState & RESOURCE_STATE_GENERIC_READ) == 0, "Unordered access state is not compatible with any input state"); + UnbindTextureFromInput(pTextureD3D11Impl, pTextureD3D11Impl->GetD3D11Texture()); + } + + if ((Barrier.NewState & RESOURCE_STATE_GENERIC_READ) != 0) + { + if ((OldState & RESOURCE_STATE_RENDER_TARGET) !=0 ) + UnbindTextureFromRenderTarget(pTextureD3D11Impl); + + if ((OldState & RESOURCE_STATE_DEPTH_WRITE) !=0 ) + UnbindTextureFromDepthStencil(pTextureD3D11Impl); + + if ((OldState & RESOURCE_STATE_UNORDERED_ACCESS) != 0) + { + UnbindResourceFromUAV(pTextureD3D11Impl, pTextureD3D11Impl->GetD3D11Texture()); + pTextureD3D11Impl->ClearState(RESOURCE_STATE_UNORDERED_ACCESS); + } + } + if (Barrier.UpdateResourceState) + { + pTextureD3D11Impl->SetState(Barrier.NewState); + } + } + else + { + VERIFY_EXPR(Barrier.pBuffer); + auto* pBufferD3D11Impl = ValidatedCast(Barrier.pBuffer); + auto OldState = Barrier.OldState; + if (OldState == RESOURCE_STATE_UNKNOWN) + { + if (pBufferD3D11Impl->IsInKnownState()) + { + OldState = pBufferD3D11Impl->GetState(); + } + else + { + LOG_ERROR_MESSAGE("Failed to transition the state of buffer '", pBufferD3D11Impl->GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); + continue; + } + } + else + { + if (pBufferD3D11Impl->IsInKnownState() && pBufferD3D11Impl->GetState() != OldState) + { + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(pBufferD3D11Impl->GetState()), " of buffer '", + pBufferD3D11Impl->GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); + } + } + + if ((Barrier.NewState & RESOURCE_STATE_UNORDERED_ACCESS) != 0) + { + DEV_CHECK_ERR((Barrier.NewState & RESOURCE_STATE_GENERIC_READ) == 0, "Unordered access state is not compatible with any input state"); + UnbindBufferFromInput(pBufferD3D11Impl, pBufferD3D11Impl->m_pd3d11Buffer); + } + + if ((Barrier.NewState & RESOURCE_STATE_GENERIC_READ) != 0) + { + UnbindResourceFromUAV(pBufferD3D11Impl, pBufferD3D11Impl->m_pd3d11Buffer); + } + + if (Barrier.UpdateResourceState) + { + pBufferD3D11Impl->SetState(Barrier.NewState); + } + } + } } #ifdef VERIFY_CONTEXT_BINDINGS diff --git a/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp index cb257437..c53da496 100644 --- a/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp @@ -41,6 +41,7 @@ TextureBaseD3D11 :: TextureBaseD3D11(IReferenceCounters* pRefCounters, { if( TexDesc.Usage == USAGE_STATIC && InitData.pSubResources == nullptr ) LOG_ERROR_AND_THROW("Static Texture must be initialized with data at creation time"); + SetState(RESOURCE_STATE_UNDEFINED); } IMPLEMENT_QUERY_INTERFACE( TextureBaseD3D11, IID_TextureD3D11, TTextureBase ) diff --git a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp index f6c1e281..8d6d5d9c 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp @@ -238,7 +238,7 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) // D3D12_RESOURCE_STATE_GENERIC_READ state if (pBufferD3D12Impl->GetDesc().Usage == USAGE_DYNAMIC && (pBufferD3D12Impl->GetDesc().BindFlags & (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) == 0) { - DEV_CHECK_ERR(pBufferD3D12Impl->GetState() == D3D12_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers that cannot be bound as SRV or UAV are expected to always be in D3D12_RESOURCE_STATE_GENERIC_READ state"); + DEV_CHECK_ERR(pBufferD3D12Impl->GetState() == RESOURCE_STATE_GENERIC_READ, "Dynamic buffers that cannot be bound as SRV or UAV are expected to always be in D3D12_RESOURCE_STATE_GENERIC_READ state"); VERIFY( (Barrier.NewState & RESOURCE_STATE_GENERIC_READ) == Barrier.NewState, "Dynamic buffers can only transition to one of RESOURCE_STATE_GENERIC_READ states"); } #endif @@ -274,21 +274,13 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) if (pTextureD3D12Impl) { const auto& TexDesc = pTextureD3D12Impl->GetDesc(); -#ifdef DEVELOPMENT - { - DEV_CHECK_ERR(Barrier.FirstMipLevel < TexDesc.MipLevels, "First mip level (", Barrier.FirstMipLevel, ") specified by the barrier is " - "out of range. Texture \'", TexDesc.Name, "\' has only ", TexDesc.MipLevels, " mip level(s)"); - DEV_CHECK_ERR(Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels || Barrier.FirstMipLevel + Barrier.MipLevelsCount < TexDesc.MipLevels, - "Mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel+Barrier.MipLevelsCount-1, " " - "specified by the barrier is out of range. Texture \'", TexDesc.Name, "\' has only ", TexDesc.MipLevels, " mip level(s)"); - - DEV_CHECK_ERR(Barrier.FirstArraySlice < TexDesc.ArraySize, "First array slice (", Barrier.FirstArraySlice, ") specified by the barrier is " - "out of range. Array size of texture \'", TexDesc.Name, "\' is ", TexDesc.ArraySize); - DEV_CHECK_ERR(Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices || Barrier.FirstArraySlice + Barrier.ArraySliceCount < TexDesc.ArraySize, - "Array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice+Barrier.ArraySliceCount-1, " " - "specified by the barrier is out of range. Array size of texture \'", TexDesc.Name, "\' is ", TexDesc.ArraySize); - } -#endif + VERIFY(Barrier.FirstMipLevel < TexDesc.MipLevels, "First mip level is out of range"); + VERIFY(Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels || Barrier.FirstMipLevel + Barrier.MipLevelsCount < TexDesc.MipLevels, + "Invalid mip level range "); + VERIFY(Barrier.FirstArraySlice < TexDesc.ArraySize, "First array slice is out of range"); + VERIFY(Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices || Barrier.FirstArraySlice + Barrier.ArraySliceCount < TexDesc.ArraySize, + "Invalid array slice range "); + if (Barrier.FirstMipLevel == 0 && (Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels || Barrier.MipLevelsCount == TexDesc.MipLevels) && Barrier.FirstArraySlice == 0 && (Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices || Barrier.ArraySliceCount == TexDesc.ArraySize)) { diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 48f875e9..76e37ff5 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -1120,7 +1120,12 @@ namespace Diligent { auto& CmdCtx = GetCmdContext(); for(Uint32 i = 0; i < BarrierCount; ++i) + { +#ifdef DEVELOPMENT + DvpVerifyStateTransitionDesc(pResourceBarriers[i]); +#endif CmdCtx.TransitionResource(pResourceBarriers[i]); + } } void DeviceContextD3D12Impl::TransitionTextureState(ITexture *pTexture, D3D12_RESOURCE_STATES State) diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d9cc8bf6..5e2402f7 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1648,9 +1648,6 @@ namespace Diligent void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, bool UpdateBufferState) { - DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); - VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); - EnsureVkCmdBuffer(); if (OldState == RESOURCE_STATE_UNKNOWN) { @@ -1673,15 +1670,20 @@ namespace Diligent " specified by the barrier"); } } - DEV_CHECK_ERR((OldState & NewState) != NewState, "The buffer is already in requested state"); - auto vkBuff = BufferVk.GetVkBuffer(); - auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); - auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); - m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags); - if (UpdateBufferState) + if ((OldState & NewState) != NewState) { - BufferVk.SetState(NewState); + DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); + VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); + + auto vkBuff = BufferVk.GetVkBuffer(); + auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); + auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); + m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags); + if (UpdateBufferState) + { + BufferVk.SetState(NewState); + } } } @@ -1704,28 +1706,12 @@ namespace Diligent for(Uint32 i=0; i < BarrierCount; ++i) { const auto& Barrier = pResourceBarriers[i]; - DEV_CHECK_ERR( (Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer must not be null"); - DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); +#ifdef DEVELOPMENT + DvpVerifyStateTransitionDesc(Barrier); +#endif if (Barrier.pTexture) { auto* pTextureVkImpl = ValidatedCast(Barrier.pTexture); -#ifdef DEVELOPMENT - { - const auto& TexDesc = pTextureVkImpl->GetDesc(); - DEV_CHECK_ERR(Barrier.FirstMipLevel < TexDesc.MipLevels, "First mip level (", Barrier.FirstMipLevel, ") specified by the barrier is " - "out of range. Texture \'", TexDesc.Name, "\' has only ", TexDesc.MipLevels, " mip level(s)"); - DEV_CHECK_ERR(Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels || Barrier.FirstMipLevel + Barrier.MipLevelsCount < TexDesc.MipLevels, - "Mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel+Barrier.MipLevelsCount-1, " " - "specified by the barrier is out of range. Texture \'", TexDesc.Name, "\' has only ", TexDesc.MipLevels, " mip level(s)"); - - DEV_CHECK_ERR(Barrier.FirstArraySlice < TexDesc.ArraySize, "First array slice (", Barrier.FirstArraySlice, ") specified by the barrier is " - "out of range. Array size of texture \'", TexDesc.Name, "\' is ", TexDesc.ArraySize); - DEV_CHECK_ERR(Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices || Barrier.FirstArraySlice + Barrier.ArraySliceCount < TexDesc.ArraySize, - "Array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice+Barrier.ArraySliceCount-1, " " - "specified by the barrier is out of range. Array size of texture \'", TexDesc.Name, "\' is ", TexDesc.ArraySize); - } -#endif - VkImageSubresourceRange SubResRange; SubResRange.aspectMask = 0; SubResRange.baseMipLevel = Barrier.FirstMipLevel; -- cgit v1.2.3