From c6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 7 Feb 2021 12:50:39 -0800 Subject: Reworked ExecuteCommandList(s) to take multiple command lists instead of one --- .../include/CommandQueueD3D12Impl.hpp | 3 +- .../include/DeviceContextD3D12Impl.hpp | 5 ++- .../include/RenderDeviceD3D12Impl.hpp | 9 +++-- .../interface/CommandQueueD3D12.h | 11 ++++-- .../src/CommandQueueD3D12Impl.cpp | 16 ++++++-- .../src/DeviceContextD3D12Impl.cpp | 40 +++++++++++++++---- .../src/RenderDeviceD3D12Impl.cpp | 46 ++++++++++++++++------ 7 files changed, 97 insertions(+), 33 deletions(-) (limited to 'Graphics/GraphicsEngineD3D12') diff --git a/Graphics/GraphicsEngineD3D12/include/CommandQueueD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/CommandQueueD3D12Impl.hpp index 4211d384..20f81af3 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandQueueD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/CommandQueueD3D12Impl.hpp @@ -52,7 +52,8 @@ public: virtual Uint64 DILIGENT_CALL_TYPE GetNextFenceValue() const override final { return m_NextFenceValue; } // Implementation of ICommandQueueD3D12::Submit(). - virtual Uint64 DILIGENT_CALL_TYPE Submit(ID3D12GraphicsCommandList* commandList) override final; + virtual Uint64 DILIGENT_CALL_TYPE Submit(Uint32 NumCommandLists, + ID3D12CommandList* const* ppCommandLists) override final; // Implementation of ICommandQueueD3D12::GetD3D12CommandQueue(). virtual ID3D12CommandQueue* DILIGENT_CALL_TYPE GetD3D12CommandQueue() override final { return m_pd3d12CmdQueue; } diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp index de33a7ff..15c85492 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp @@ -234,8 +234,9 @@ public: /// Implementation of IDeviceContext::FinishCommandList() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE FinishCommandList(class ICommandList** ppCommandList) override final; - /// Implementation of IDeviceContext::ExecuteCommandList() in Direct3D12 backend. - virtual void DILIGENT_CALL_TYPE ExecuteCommandList(class ICommandList* pCommandList) override final; + /// Implementation of IDeviceContext::ExecuteCommandLists() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) override final; /// Implementation of IDeviceContext::SignalFence() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE SignalFence(IFence* pFence, Uint64 Value) override final; diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index 984afd41..707e59c0 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -174,10 +174,11 @@ public: void CloseAndExecuteTransientCommandContext(Uint32 CommandQueueIndex, PooledCommandContext&& Ctx); - Uint64 CloseAndExecuteCommandContext(Uint32 QueueIndex, - PooledCommandContext&& Ctx, - bool DiscardStaleObjects, - std::vector>>* pSignalFences); + Uint64 CloseAndExecuteCommandContexts(Uint32 QueueIndex, + Uint32 NumContexts, + PooledCommandContext pContexts[], + bool DiscardStaleObjects, + std::vector>>* pSignalFences); void SignalFences(Uint32 QueueIndex, std::vector>>& SignalFences); diff --git a/Graphics/GraphicsEngineD3D12/interface/CommandQueueD3D12.h b/Graphics/GraphicsEngineD3D12/interface/CommandQueueD3D12.h index c9d09d34..9b1ff33a 100644 --- a/Graphics/GraphicsEngineD3D12/interface/CommandQueueD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/CommandQueueD3D12.h @@ -53,11 +53,16 @@ DILIGENT_BEGIN_INTERFACE(ICommandQueueD3D12, IObject) /// Returns the fence value that will be signaled next time VIRTUAL Uint64 METHOD(GetNextFenceValue)(THIS) CONST PURE; - /// Executes a given command list + /// Submits command lists for execution. - /// \return Fence value associated with the executed command list + /// \param[in] NumCommandLists - The number of command lists to submit. + /// \param[in] ppCommandLists - A pointer to the array of NumCommandLists command + /// lists to submit. + /// + /// \return Fence value associated with the executed command lists. VIRTUAL Uint64 METHOD(Submit)(THIS_ - ID3D12GraphicsCommandList* commandList) PURE; + Uint32 NumCommandLists, + ID3D12CommandList* const* ppCommandLists) PURE; /// Returns D3D12 command queue. May return null if queue is anavailable VIRTUAL ID3D12CommandQueue* METHOD(GetD3D12CommandQueue)(THIS) PURE; diff --git a/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp index 25d8362c..cedf76f7 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp @@ -51,7 +51,8 @@ CommandQueueD3D12Impl::~CommandQueueD3D12Impl() CloseHandle(m_WaitForGPUEventHandle); } -Uint64 CommandQueueD3D12Impl::Submit(ID3D12GraphicsCommandList* commandList) +Uint64 CommandQueueD3D12Impl::Submit(Uint32 NumCommandLists, + ID3D12CommandList* const* ppCommandLists) { std::lock_guard Lock{m_QueueMtx}; @@ -59,10 +60,17 @@ Uint64 CommandQueueD3D12Impl::Submit(ID3D12GraphicsCommandList* commandList) // Increment the value before submitting the list Atomics::AtomicIncrement(m_NextFenceValue); - if (commandList != nullptr) + // Render device submits null command list to signal the fence and + // discard all resources. + if (NumCommandLists != 0 && ppCommandLists != nullptr) { - ID3D12CommandList* const ppCmdLists[] = {commandList}; - m_pd3d12CmdQueue->ExecuteCommandLists(1, ppCmdLists); +#ifdef DILIGENT_DEBUG + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + VERIFY(ppCommandLists[i] != nullptr, "Command list must not be null"); + } +#endif + m_pd3d12CmdQueue->ExecuteCommandLists(NumCommandLists, ppCommandLists); } // Signal the fence. This must be done atomically with command list submission. diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index ec14d2f5..b7415753 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -26,7 +26,10 @@ */ #include "pch.h" + #include +#include + #include "RenderDeviceD3D12Impl.hpp" #include "DeviceContextD3D12Impl.hpp" #include "PipelineStateD3D12Impl.hpp" @@ -778,7 +781,8 @@ void DeviceContextD3D12Impl::Flush(bool RequestNewCmdCtx) if (m_State.NumCommands != 0) { m_CurrCmdCtx->FlushResourceBarriers(); - m_pDevice->CloseAndExecuteCommandContext(m_CommandQueueId, std::move(m_CurrCmdCtx), true, &m_PendingFences); + m_pDevice->CloseAndExecuteCommandContexts(m_CommandQueueId, 1, &m_CurrCmdCtx, true, &m_PendingFences); + VERIFY(!m_CurrCmdCtx, "Context must be disposed by CloseAndExecuteCommandContexts"); m_PendingFences.clear(); } else @@ -2041,25 +2045,45 @@ void DeviceContextD3D12Impl::FinishCommandList(ICommandList** ppCommandList) InvalidateState(); } -void DeviceContextD3D12Impl::ExecuteCommandList(ICommandList* pCommandList) +void DeviceContextD3D12Impl::ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) { if (m_bIsDeferred) { LOG_ERROR_MESSAGE("Only immediate context can execute command list"); return; } + + if (NumCommandLists == 0) + return; + DEV_CHECK_ERR(ppCommandLists != nullptr, "ppCommandLists must not be null when NumCommandLists is not zero"); + // First execute commands in this context Flush(true); InvalidateState(); - CommandListD3D12Impl* pCmdListD3D12 = ValidatedCast(pCommandList); VERIFY_EXPR(m_PendingFences.empty()); - RefCntAutoPtr pDeferredCtx; - auto CmdContext = pCmdListD3D12->Close(pDeferredCtx); - m_pDevice->CloseAndExecuteCommandContext(m_CommandQueueId, std::move(CmdContext), true, nullptr); - // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context - pDeferredCtx->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; + + // TODO: use small_vector + std::vector Contexts; + Contexts.reserve(NumCommandLists); + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + auto* const pCmdListD3D12 = ValidatedCast(ppCommandLists[i]); + + RefCntAutoPtr pDeferredCtx; + Contexts.emplace_back(pCmdListD3D12->Close(pDeferredCtx)); + // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context + pDeferredCtx->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; + } + + m_pDevice->CloseAndExecuteCommandContexts(m_CommandQueueId, NumCommandLists, Contexts.data(), true, nullptr); + +#ifdef DILIGENT_DEBUG + for (Uint32 i = 0; i < NumCommandLists; ++i) + VERIFY(!Contexts[i], "All contexts must be disposed by CloseAndExecuteCommandContexts"); +#endif } void DeviceContextD3D12Impl::SignalFence(IFence* pFence, Uint64 Value) diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 14339102..8b22a8c3 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -26,7 +26,10 @@ */ #include "pch.h" + #include +#include + #include "RenderDeviceD3D12Impl.hpp" #include "PipelineStateD3D12Impl.hpp" #include "ShaderD3D12Impl.hpp" @@ -406,22 +409,41 @@ void RenderDeviceD3D12Impl::FreeCommandContext(PooledCommandContext&& Ctx) void RenderDeviceD3D12Impl::CloseAndExecuteTransientCommandContext(Uint32 CommandQueueIndex, PooledCommandContext&& Ctx) { CComPtr pAllocator; - ID3D12GraphicsCommandList* pCmdList = Ctx->Close(pAllocator); - Uint64 FenceValue = 0; + ID3D12CommandList* const pCmdList = Ctx->Close(pAllocator); + VERIFY(pCmdList != nullptr, "Command list must not be null"); + Uint64 FenceValue = 0; // Execute command list directly through the queue to avoid interference with command list numbers in the queue LockCmdQueueAndRun(CommandQueueIndex, [&](ICommandQueueD3D12* pCmdQueue) // { - FenceValue = pCmdQueue->Submit(pCmdList); + FenceValue = pCmdQueue->Submit(1, &pCmdList); }); m_CmdListManager.ReleaseAllocator(std::move(pAllocator), CommandQueueIndex, FenceValue); FreeCommandContext(std::move(Ctx)); } -Uint64 RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(Uint32 QueueIndex, PooledCommandContext&& Ctx, bool DiscardStaleObjects, std::vector>>* pSignalFences) +Uint64 RenderDeviceD3D12Impl::CloseAndExecuteCommandContexts(Uint32 QueueIndex, + Uint32 NumContexts, + PooledCommandContext pContexts[], + bool DiscardStaleObjects, + std::vector>>* pSignalFences) { - CComPtr pAllocator; - ID3D12GraphicsCommandList* pCmdList = Ctx->Close(pAllocator); + VERIFY_EXPR(NumContexts > 0 && pContexts != 0); + + // TODO: use small_vector + std::vector d3d12CmdLists; + std::vector> CmdAllocators; + d3d12CmdLists.reserve(NumContexts); + CmdAllocators.reserve(NumContexts); + + for (Uint32 i = 0; i < NumContexts; ++i) + { + auto& pCtx = pContexts[i]; + VERIFY_EXPR(pCtx); + CComPtr pAllocator; + d3d12CmdLists.emplace_back(pCtx->Close(pAllocator)); + CmdAllocators.emplace_back(std::move(pAllocator)); + } Uint64 FenceValue = 0; { @@ -443,14 +465,17 @@ Uint64 RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(Uint32 QueueIndex, P // | N+1, but resource it references | | // | was added to the delete queue | | // | with number N | | - auto SubmittedCmdBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, pCmdList, true); + auto SubmittedCmdBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, true, NumContexts, d3d12CmdLists.data()); FenceValue = SubmittedCmdBuffInfo.FenceValue; if (pSignalFences != nullptr) SignalFences(QueueIndex, *pSignalFences); } - m_CmdListManager.ReleaseAllocator(std::move(pAllocator), QueueIndex, FenceValue); - FreeCommandContext(std::move(Ctx)); + for (Uint32 i = 0; i < NumContexts; ++i) + { + m_CmdListManager.ReleaseAllocator(std::move(CmdAllocators[i]), QueueIndex, FenceValue); + FreeCommandContext(std::move(pContexts[i])); + } PurgeReleaseQueue(QueueIndex); @@ -477,8 +502,7 @@ void RenderDeviceD3D12Impl::FlushStaleResources(Uint32 CmdQueueIndex) { // Submit empty command list to the queue. This will effectively signal the fence and // discard all resources - ID3D12GraphicsCommandList* pNullCmdList = nullptr; - TRenderDeviceBase::SubmitCommandBuffer(CmdQueueIndex, pNullCmdList, true); + TRenderDeviceBase::SubmitCommandBuffer(CmdQueueIndex, true, 0, nullptr); } void RenderDeviceD3D12Impl::ReleaseStaleResources(bool ForceRelease) -- cgit v1.2.3