diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-12-23 06:56:19 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-12-23 06:56:19 +0000 |
| commit | d80f5d9b2d769fd0513ae0e026d8a56b5d56a1fe (patch) | |
| tree | f4c2d1959618a7e69c23a3819dce15431034d68d /Graphics | |
| parent | Added clamp() function to math lib (diff) | |
| download | DiligentCore-d80f5d9b2d769fd0513ae0e026d8a56b5d56a1fe.tar.gz DiligentCore-d80f5d9b2d769fd0513ae0e026d8a56b5d56a1fe.zip | |
Implemented split barriers (closed https://github.com/DiligentGraphics/DiligentCore/issues/43).
Diffstat (limited to 'Graphics')
5 files changed, 100 insertions, 21 deletions
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.h b/Graphics/GraphicsEngine/include/DeviceContextBase.h index 959eafae..51420d83 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.h +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.h @@ -934,12 +934,13 @@ void DeviceContextBase<BaseInterface,ImplementationTraits> :: { 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"); + RESOURCE_STATE OldState = RESOURCE_STATE_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(); + 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, "'"); @@ -968,10 +969,20 @@ void DeviceContextBase<BaseInterface,ImplementationTraits> :: { 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(); + 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, "'"); } + + if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) + { + DEV_CHECK_ERR(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "For UAV barriers, transition type must be STATE_TRANSITION_TYPE_IMMEDIATE"); + } + + if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) + { + DEV_CHECK_ERR(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier"); + } } template<typename BaseInterface, typename ImplementationTraits> diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index d515b2a1..1e605009 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1659,6 +1659,24 @@ namespace Diligent RESOURCE_STATE_COPY_SOURCE }; + /// State transition barrier type + enum STATE_TRANSITION_TYPE : Uint8 + { + /// Perform state transition immediately. + STATE_TRANSITION_TYPE_IMMEDIATE = 0, + + /// Begin split barrier. This mode only has effect in Direct3D12 backend, and corresponds to + /// [D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY](https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ne-d3d12-d3d12_resource_barrier_flags) + /// flag. See https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#split-barriers. + /// In other backends, begin-split barriers are ignored. + STATE_TRANSITION_TYPE_BEGIN, + + /// End split barrier. This mode only has effect in Direct3D12 backend, and corresponds to + /// [D3D12_RESOURCE_BARRIER_FLAG_END_ONLY](https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ne-d3d12-d3d12_resource_barrier_flags) + /// flag. See https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#split-barriers. + /// In other backends, this mode is similar to STATE_TRANSITION_TYPE_IMMEDIATE. + STATE_TRANSITION_TYPE_END + }; /// Resource state transition barrier description struct StateTransitionDesc @@ -1693,25 +1711,31 @@ namespace Diligent /// Resource state after transition. RESOURCE_STATE NewState = RESOURCE_STATE_UNKNOWN; + /// State transition type, see Diligent::STATE_TRANSITION_TYPE. + + /// \note When issuing UAV barrier (i.e. OldState and NewState equal RESOURCE_STATE_UNORDERED_ACCESS), + /// TransitionType must be STATE_TRANSITION_TYPE_IMMEDIATE. + STATE_TRANSITION_TYPE TransitionType = STATE_TRANSITION_TYPE_IMMEDIATE; + /// If set to true, the internal resource state will be set to NewState and the engine - /// will be able to take the resource state management. In this case it is the + /// will be able to take over the resource state management. In this case it is the /// responsibility of the application to make sure that all subresources are indeed in /// designated state. - /// If set to false, internal resource state will be set to RESOURCE_STATE_UNKNOWN, and the - /// engine will not manage or check the resource state in all further operations until the - /// state is set to a known value. + /// If set to false, internal resource state will be unchanged. + /// \note When TransitionType is STATE_TRANSITION_TYPE_BEGIN, this member must be false. bool UpdateResourceState = false; StateTransitionDesc(){} - StateTransitionDesc(ITexture* _pTexture, - RESOURCE_STATE _OldState, - RESOURCE_STATE _NewState, - Uint32 _FirstMipLevel = 0, - Uint32 _MipLevelsCount = RemainingMipLevels, - Uint32 _FirstArraySlice = 0, - Uint32 _ArraySliceCount = RemainingArraySlices, - bool _UpdateState = false) : + StateTransitionDesc(ITexture* _pTexture, + RESOURCE_STATE _OldState, + RESOURCE_STATE _NewState, + Uint32 _FirstMipLevel = 0, + Uint32 _MipLevelsCount = RemainingMipLevels, + Uint32 _FirstArraySlice = 0, + Uint32 _ArraySliceCount = RemainingArraySlices, + STATE_TRANSITION_TYPE _TransitionType = STATE_TRANSITION_TYPE_IMMEDIATE, + bool _UpdateState = false) : pTexture (_pTexture), FirstMipLevel (_FirstMipLevel), MipLevelsCount (_MipLevelsCount), @@ -1719,6 +1743,7 @@ namespace Diligent ArraySliceCount (_ArraySliceCount), OldState (_OldState), NewState (_NewState), + TransitionType (_TransitionType), UpdateResourceState (_UpdateState) {} @@ -1726,7 +1751,7 @@ namespace Diligent RESOURCE_STATE _OldState, RESOURCE_STATE _NewState, bool _UpdateState) : - StateTransitionDesc(_pTexture, _OldState, _NewState, 0, RemainingMipLevels, 0, RemainingArraySlices, _UpdateState) + StateTransitionDesc(_pTexture, _OldState, _NewState, 0, RemainingMipLevels, 0, RemainingArraySlices, STATE_TRANSITION_TYPE_IMMEDIATE, _UpdateState) {} StateTransitionDesc(IBuffer* _pBuffer, diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index e04686a9..8ee4090b 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -1871,6 +1871,14 @@ namespace Diligent 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.TransitionType == STATE_TRANSITION_TYPE_BEGIN)
+ {
+ // Skip begin-split barriers
+ VERIFY(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier");
+ continue;
+ }
+ VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type");
+
if (Barrier.pTexture)
{
auto* pTextureD3D11Impl = ValidatedCast<TextureBaseD3D11>(Barrier.pTexture);
diff --git a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp index 71859d23..a007a01f 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp @@ -120,6 +120,24 @@ void CommandContext::InsertUAVBarrier(ID3D12Resource* pd3d12Resource) BarrierDesc.UAV.pResource = pd3d12Resource; } +static D3D12_RESOURCE_BARRIER_FLAGS TransitionTypeToD3D12ResourceBarrierFlag(STATE_TRANSITION_TYPE TransitionType) +{ + switch(TransitionType) + { + case STATE_TRANSITION_TYPE_IMMEDIATE: + return D3D12_RESOURCE_BARRIER_FLAG_NONE; + + case STATE_TRANSITION_TYPE_BEGIN: + return D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY; + + case STATE_TRANSITION_TYPE_END: + return D3D12_RESOURCE_BARRIER_FLAG_END_ONLY; + + default: + UNEXPECTED("Unexpected state transition type"); + return D3D12_RESOURCE_BARRIER_FLAG_NONE; + } +} void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) { @@ -175,8 +193,8 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) NewState = static_cast<RESOURCE_STATE>(OldState | NewState); D3D12_RESOURCE_BARRIER BarrierDesc; - BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + BarrierDesc.Flags = TransitionTypeToD3D12ResourceBarrierFlag(Barrier.TransitionType); BarrierDesc.Transition.pResource = pd3d12Resource; BarrierDesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; BarrierDesc.Transition.StateBefore = ResourceStateFlagsToD3D12ResourceStates(OldState); @@ -217,13 +235,21 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) if (pTextureD3D12Impl) { - pTextureD3D12Impl->SetState(Barrier.UpdateResourceState ? NewState : RESOURCE_STATE_UNKNOWN); + VERIFY(!Barrier.UpdateResourceState || (Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END), "Texture state can't be updated in begin-split barrier"); + if (Barrier.UpdateResourceState) + { + pTextureD3D12Impl->SetState(NewState); + } } else { VERIFY_EXPR(pBufferD3D12Impl); - pBufferD3D12Impl->SetState(Barrier.UpdateResourceState ? NewState : RESOURCE_STATE_UNKNOWN); + VERIFY(!Barrier.UpdateResourceState || (Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END), "Buffer state can't be updated in begin-split barrier"); + if (Barrier.UpdateResourceState) + { + pBufferD3D12Impl->SetState(NewState); + } if (pBufferD3D12Impl->GetDesc().Usage == USAGE_DYNAMIC && (pBufferD3D12Impl->GetDesc().BindFlags & (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) == 0) VERIFY(pBufferD3D12Impl->GetState() == RESOURCE_STATE_GENERIC_READ, "Dynamic buffers without SRV/UAV bind flag are expected to never transition from RESOURCE_STATE_GENERIC_READ state"); @@ -232,6 +258,7 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) { + DEV_CHECK_ERR(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "UAV barriers must not be split"); InsertUAVBarrier(pd3d12Resource); } diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 856d20ca..b34daae6 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1859,7 +1859,6 @@ namespace Diligent void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, bool UpdateBufferState) { - EnsureVkCmdBuffer(); if (OldState == RESOURCE_STATE_UNKNOWN) { if (BufferVk.IsInKnownState()) @@ -1889,6 +1888,7 @@ namespace Diligent DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); + EnsureVkCmdBuffer(); auto vkBuff = BufferVk.GetVkBuffer(); auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); @@ -1936,7 +1936,7 @@ namespace Diligent void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { - if(BarrierCount == 0) + if (BarrierCount == 0) return; EnsureVkCmdBuffer(); @@ -1947,6 +1947,14 @@ namespace Diligent #ifdef DEVELOPMENT DvpVerifyStateTransitionDesc(Barrier); #endif + if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) + { + // Skip begin-split barriers + VERIFY(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier"); + continue; + } + VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type"); + if (Barrier.pTexture) { auto* pTextureVkImpl = ValidatedCast<TextureVkImpl>(Barrier.pTexture); |
