From d06553e2b4700aa026acd4445a598eadf10dfb35 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sun, 8 Sep 2019 17:42:51 -0700 Subject: Added IDeviceContext::WaitForIdle() method (updated API version to 240028) --- Graphics/GraphicsEngine/interface/APIInfo.h | 2 +- Graphics/GraphicsEngine/interface/DeviceContext.h | 9 ++++ .../include/DeviceContextD3D11Impl.h | 6 ++- .../src/DeviceContextD3D11Impl.cpp | 26 ++++++++++-- .../include/DeviceContextD3D12Impl.h | 6 ++- .../src/DeviceContextD3D12Impl.cpp | 6 +++ .../src/RenderDeviceD3D12Impl.cpp | 2 +- .../include/DeviceContextMtlImpl.h | 6 ++- .../src/DeviceContextMtlImpl.mm | 8 ++++ .../include/RenderDeviceNextGenBase.h | 48 ++++++++++++---------- .../include/DeviceContextGLImpl.h | 6 ++- .../src/DeviceContextGLImpl.cpp | 6 +++ .../src/GLProgramResources.cpp | 2 +- .../include/DeviceContextVkImpl.h | 6 ++- .../src/DeviceContextVkImpl.cpp | 6 +++ .../src/RenderDeviceVkImpl.cpp | 2 +- 16 files changed, 108 insertions(+), 39 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index 82ff31e0..d4215993 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -26,7 +26,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 240027 +#define DILIGENT_API_VERSION 240028 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index ea40f058..b3b9dbb7 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -821,6 +821,15 @@ public: virtual void WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext) = 0; + /// Submits all outstanding commands for execution to the GPU and waits until they are complete. + + /// \remarks Only immediate contexts can be idled.\n + /// The methods implicitly flushes the context (see IDeviceContext::Flush()), so an + /// application must explicitly reset the PSO and bind all required shader resources after + /// idling the context.\n + virtual void WaitForIdle() = 0; + + /// Submits all pending commands in the context for execution to the command queue. /// \remarks Only immediate contexts can be flushed.\n diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h index 940529b4..86ca2fb2 100755 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.h @@ -103,8 +103,6 @@ public: virtual void ClearRenderTarget(ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)override final; - virtual void Flush()override final; - virtual void UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, @@ -158,6 +156,10 @@ public: virtual void WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext)override final; + virtual void WaitForIdle()override final; + + virtual void Flush()override final; + virtual ID3D11DeviceContext* GetD3D11DeviceContext()override final { return m_pd3d11DeviceContext; } void CommitRenderTargets(); diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 72e26117..e3543bac 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -1747,20 +1747,28 @@ namespace Diligent #endif } - void DeviceContextD3D11Impl::SignalFence(IFence* pFence, Uint64 Value) + + static CComPtr CreateD3D11QueryEvent(ID3D11Device* pd3d11Device) { - VERIFY(!m_bIsDeferred, "Fence can only be signaled from immediate context"); - auto* pd3d11Device = m_pDevice.RawPtr()->GetD3D11Device(); D3D11_QUERY_DESC QueryDesc = {}; QueryDesc.Query = D3D11_QUERY_EVENT; // Determines whether or not the GPU is finished processing commands. // When the GPU is finished processing commands ID3D11DeviceContext::GetData will // return S_OK, and pData will point to a BOOL with a value of TRUE. When using this // type of query, ID3D11DeviceContext::Begin is disabled. QueryDesc.MiscFlags = 0; + CComPtr pd3d11Query; auto hr = pd3d11Device->CreateQuery(&QueryDesc, &pd3d11Query); DEV_CHECK_ERR(SUCCEEDED(hr), "Failed to create D3D11 query"); VERIFY_EXPR(pd3d11Query); + return pd3d11Query; + } + + void DeviceContextD3D11Impl::SignalFence(IFence* pFence, Uint64 Value) + { + VERIFY(!m_bIsDeferred, "Fence can only be signaled from immediate context"); + auto* pd3d11Device = m_pDevice.RawPtr()->GetD3D11Device(); + CComPtr pd3d11Query = CreateD3D11QueryEvent(pd3d11Device); m_pd3d11DeviceContext->End(pd3d11Query); auto* pFenceD3D11Impl = ValidatedCast(pFence); pFenceD3D11Impl->AddPendingQuery(m_pd3d11DeviceContext, std::move(pd3d11Query), Value); @@ -1775,6 +1783,18 @@ namespace Diligent pFenceD3D11Impl->Wait(Value, FlushContext); } + void DeviceContextD3D11Impl::WaitForIdle() + { + VERIFY(!m_bIsDeferred, "Only immediate contexts can be idled"); + Flush(); + auto* pd3d11Device = m_pDevice.RawPtr()->GetD3D11Device(); + CComPtr pd3d11Query = CreateD3D11QueryEvent(pd3d11Device); + m_pd3d11DeviceContext->End(pd3d11Query); + BOOL Data; + while (m_pd3d11DeviceContext->GetData(pd3d11Query, &Data, sizeof(Data), 0) != S_OK) + std::this_thread::yield(); + } + void DeviceContextD3D11Impl::ClearStateCache() { TDeviceContextBase::ClearStateCache(); diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h index b9f57598..0d973062 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h @@ -104,8 +104,6 @@ public: virtual void ClearRenderTarget( ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode )override final; - virtual void Flush()override final; - virtual void UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, @@ -156,6 +154,10 @@ public: virtual void WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext)override final; + virtual void WaitForIdle()override final; + + virtual void Flush()override final; + virtual void TransitionTextureState(ITexture *pTexture, D3D12_RESOURCE_STATES State)override final; virtual void TransitionBufferState(IBuffer *pBuffer, D3D12_RESOURCE_STATES State)override final; diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index b31bedef..78e81459 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -1580,6 +1580,12 @@ namespace Diligent pFenceD3D12->WaitForCompletion(Value); } + void DeviceContextD3D12Impl::WaitForIdle() + { + VERIFY(!m_bIsDeferred, "Only immediate contexts can be idled"); + Flush(); + m_pDevice.RawPtr()->IdleCommandQueue(m_CommandQueueId, true); + } void DeviceContextD3D12Impl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index e34b637a..22ed2bc8 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -202,7 +202,7 @@ void RenderDeviceD3D12Impl::SignalFences(Uint32 QueueIndex, std::vector Lock(Queue.Mtx); - - if (ReleaseResources) - { - // Increment command buffer number before idling the queue. - // This will make sure that any resource released while this function - // is running will be associated with the next command buffer submission. - CmdBufferNumber = static_cast(Queue.NextCmdBufferNumber); - Atomics::AtomicIncrement(Queue.NextCmdBufferNumber); - } - - FenceValue = Queue.CmdQueue->WaitForIdle(); - } + Uint64 CmdBufferNumber = 0; + Uint64 FenceValue = 0; + { + std::lock_guard Lock(Queue.Mtx); if (ReleaseResources) { - Queue.ReleaseQueue.DiscardStaleResources(CmdBufferNumber, FenceValue); - Queue.ReleaseQueue.Purge(Queue.CmdQueue->GetCompletedFenceValue()); + // Increment command buffer number before idling the queue. + // This will make sure that any resource released while this function + // is running will be associated with the next command buffer submission. + CmdBufferNumber = static_cast(Queue.NextCmdBufferNumber); + Atomics::AtomicIncrement(Queue.NextCmdBufferNumber); } + + FenceValue = Queue.CmdQueue->WaitForIdle(); + } + + if (ReleaseResources) + { + Queue.ReleaseQueue.DiscardStaleResources(CmdBufferNumber, FenceValue); + Queue.ReleaseQueue.Purge(Queue.CmdQueue->GetCompletedFenceValue()); } } + void IdleAllCommandQueues(bool ReleaseResources) + { + for(size_t q=0; q < m_CmdQueueCount; ++q) + IdleCommandQueue(q, ReleaseResources); + } + struct SubmittedCommandBufferInfo { Uint64 CmdBufferNumber = 0; diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.h index 7b1931b1..601976ee 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.h +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.h @@ -95,8 +95,6 @@ public: virtual void ClearRenderTarget(ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)override final; - virtual void Flush()override final; - virtual void UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, @@ -152,6 +150,10 @@ public: virtual void WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext)override final; + virtual void WaitForIdle()override final; + + virtual void Flush()override final; + virtual bool UpdateCurrentGLContext()override final; void BindProgramResources(Uint32& NewMemoryBarriers, IShaderResourceBinding* pResBinding); diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index 23836746..94537d40 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -1082,6 +1082,12 @@ namespace Diligent pFenceGLImpl->Wait(Value, FlushContext); } + void DeviceContextGLImpl::WaitForIdle() + { + VERIFY(!m_bIsDeferred, "Only immediate contexts can be idled"); + glFinish(); + } + bool DeviceContextGLImpl::UpdateCurrentGLContext() { auto* pRenderDeviceGL = m_pDevice.RawPtr(); diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp b/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp index 1850255d..a8f55e27 100644 --- a/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp @@ -583,7 +583,7 @@ namespace Diligent if ( strcmp(LastBlock.Name, Name.data()) == 0) { ArraySize = std::max(ArraySize, static_cast(LastBlock.ArraySize)); - VERIFY(static_cast(SBIndex) == LastBlock.SBIndex + Ind, "Storage block indices are expected to be continuous"); + VERIFY(static_cast(SBIndex) == LastBlock.SBIndex + Ind, "Storage block indices are expected to be continuous"); LastBlock.ArraySize = ArraySize; continue; } diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index a7f02919..c220a8e5 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -112,8 +112,6 @@ public: virtual void ClearRenderTarget( ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode )override final; - virtual void Flush()override final; - virtual void UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, @@ -161,6 +159,10 @@ public: virtual void WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext)override final; + virtual void WaitForIdle()override final; + + virtual void Flush()override final; + // Transitions texture subresources from OldState to NewState, and optionally updates // internal texture state. // If OldState == RESOURCE_STATE_UNKNOWN, internal texture state is used as old state. diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 2a8cafde..4e87d6d4 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1925,6 +1925,12 @@ namespace Diligent pFenceVk->Wait(Value); } + void DeviceContextVkImpl::WaitForIdle() + { + VERIFY(!m_bIsDeferred, "Only immediate contexts can be idled"); + Flush(); + m_pDevice.RawPtr()->IdleCommandQueue(m_CommandQueueId, true); + } void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayout NewLayout) { diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 271af6e0..ca9b3200 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -281,7 +281,7 @@ Uint64 RenderDeviceVkImpl::ExecuteCommandBuffer(Uint32 QueueIndex, const VkSubmi void RenderDeviceVkImpl::IdleGPU() { - IdleCommandQueues(true); + IdleAllCommandQueues(true); m_LogicalVkDevice->WaitIdle(); ReleaseStaleResources(); } -- cgit v1.2.3