diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2021-02-07 20:50:39 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-02-07 20:50:39 +0000 |
| commit | c6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c (patch) | |
| tree | e8848a7e01b2f576c11e9f9acfee6eca9fcdd681 /Graphics | |
| parent | Swap chain Vk: improved presentation mode selection (fixed https://github.com... (diff) | |
| download | DiligentCore-c6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c.tar.gz DiligentCore-c6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c.zip | |
Reworked ExecuteCommandList(s) to take multiple command lists instead of one
Diffstat (limited to 'Graphics')
18 files changed, 198 insertions, 91 deletions
diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index cd2be5a4..f268ff63 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -30,7 +30,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 240081 +#define DILIGENT_API_VERSION 240082 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 2f9408bd..411103d7 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -1836,12 +1836,14 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) ICommandList** ppCommandList) PURE; - /// Executes recorded commands in a command list. + /// Submits an array of recorded command lists for execution. - /// \param [in] pCommandList - Pointer to the command list to executre. - /// \remarks After command list is executed, it is no longer valid and should be released. - VIRTUAL void METHOD(ExecuteCommandList)(THIS_ - ICommandList* pCommandList) PURE; + /// \param [in] NumCommandLists - The number of command lists to execute. + /// \param [in] ppCommandLists - Pointer to the array of NumCommandLists command lists to execute. + /// \remarks After a command list is executed, it is no longer valid and must be released. + VIRTUAL void METHOD(ExecuteCommandLists)(THIS_ + Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) PURE; /// Tells the GPU to set a fence to a specified value after all previous work has completed. @@ -2231,7 +2233,7 @@ DILIGENT_END_INTERFACE # define IDeviceContext_ClearDepthStencil(This, ...) CALL_IFACE_METHOD(DeviceContext, ClearDepthStencil, This, __VA_ARGS__) # define IDeviceContext_ClearRenderTarget(This, ...) CALL_IFACE_METHOD(DeviceContext, ClearRenderTarget, This, __VA_ARGS__) # define IDeviceContext_FinishCommandList(This, ...) CALL_IFACE_METHOD(DeviceContext, FinishCommandList, This, __VA_ARGS__) -# define IDeviceContext_ExecuteCommandList(This, ...) CALL_IFACE_METHOD(DeviceContext, ExecuteCommandList, This, __VA_ARGS__) +# define IDeviceContext_ExecuteCommandLists(This, ...) CALL_IFACE_METHOD(DeviceContext, ExecuteCommandLists, This, __VA_ARGS__) # define IDeviceContext_SignalFence(This, ...) CALL_IFACE_METHOD(DeviceContext, SignalFence, This, __VA_ARGS__) # define IDeviceContext_WaitForFence(This, ...) CALL_IFACE_METHOD(DeviceContext, WaitForFence, This, __VA_ARGS__) # define IDeviceContext_WaitForIdle(This, ...) CALL_IFACE_METHOD(DeviceContext, WaitForIdle, This, __VA_ARGS__) diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp index 74f5dd49..3c7bf09c 100644 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp @@ -229,8 +229,9 @@ public: /// Implementation of IDeviceContext::FinishCommandList() in Direct3D11 backend. void DILIGENT_CALL_TYPE FinishCommandList(class ICommandList** ppCommandList) override final; - /// Implementation of IDeviceContext::ExecuteCommandList() in Direct3D11 backend. - virtual void DILIGENT_CALL_TYPE ExecuteCommandList(class ICommandList* pCommandList) override final; + /// Implementation of IDeviceContext::ExecuteCommandLists() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) override final; /// Implementation of IDeviceContext::SignalFence() in Direct3D11 backend. virtual void DILIGENT_CALL_TYPE SignalFence(IFence* pFence, Uint64 Value) override final; diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index b4fa4c32..7c1ae564 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -1925,7 +1925,8 @@ void DeviceContextD3D11Impl::FinishCommandList(ICommandList** ppCommandList) #endif } -void DeviceContextD3D11Impl::ExecuteCommandList(ICommandList* pCommandList) +void DeviceContextD3D11Impl::ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) { if (m_bIsDeferred) { @@ -1933,16 +1934,23 @@ void DeviceContextD3D11Impl::ExecuteCommandList(ICommandList* pCommandList) return; } - CommandListD3D11Impl* pCmdListD3D11 = ValidatedCast<CommandListD3D11Impl>(pCommandList); - auto* pd3d11CmdList = pCmdListD3D11->GetD3D11CommandList(); - m_pd3d11DeviceContext->ExecuteCommandList(pd3d11CmdList, - FALSE // A Boolean flag that determines whether the target context state is - // saved prior to and restored after the execution of a command list. - // * TRUE indicates that the runtime needs to save and restore the state. - // * FALSE indicate that no state shall be saved or restored, which causes the - // target context to return to its default state after the command list executes as if - // ID3D11DeviceContext::ClearState() was called. - ); + if (NumCommandLists == 0) + return; + DEV_CHECK_ERR(ppCommandLists != nullptr, "ppCommandLists must not be null when NumCommandLists is not zero"); + + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + auto* pCmdListD3D11 = ValidatedCast<CommandListD3D11Impl>(ppCommandLists[i]); + auto* pd3d11CmdList = pCmdListD3D11->GetD3D11CommandList(); + m_pd3d11DeviceContext->ExecuteCommandList(pd3d11CmdList, + FALSE // A Boolean flag that determines whether the target context state is + // saved prior to and restored after the execution of a command list. + // * TRUE indicates that the runtime needs to save and restore the state. + // * FALSE indicate that no state shall be saved or restored, which causes the + // target context to return to its default state after the command list executes as if + // ID3D11DeviceContext::ClearState() was called. + ); + } // Device context is now in default state InvalidateState(); 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<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pSignalFences); + Uint64 CloseAndExecuteCommandContexts(Uint32 QueueIndex, + Uint32 NumContexts, + PooledCommandContext pContexts[], + bool DiscardStaleObjects, + std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pSignalFences); void SignalFences(Uint32 QueueIndex, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>& 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<std::mutex> 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 <sstream> +#include <vector> + #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<CommandListD3D12Impl>(pCommandList); VERIFY_EXPR(m_PendingFences.empty()); - RefCntAutoPtr<DeviceContextD3D12Impl> 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<RenderDeviceD3D12Impl::PooledCommandContext> Contexts; + Contexts.reserve(NumCommandLists); + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + auto* const pCmdListD3D12 = ValidatedCast<CommandListD3D12Impl>(ppCommandLists[i]); + + RefCntAutoPtr<DeviceContextD3D12Impl> 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 <dxgi1_4.h> +#include <vector> + #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<ID3D12CommandAllocator> 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<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pSignalFences) +Uint64 RenderDeviceD3D12Impl::CloseAndExecuteCommandContexts(Uint32 QueueIndex, + Uint32 NumContexts, + PooledCommandContext pContexts[], + bool DiscardStaleObjects, + std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pSignalFences) { - CComPtr<ID3D12CommandAllocator> pAllocator; - ID3D12GraphicsCommandList* pCmdList = Ctx->Close(pAllocator); + VERIFY_EXPR(NumContexts > 0 && pContexts != 0); + + // TODO: use small_vector + std::vector<ID3D12CommandList*> d3d12CmdLists; + std::vector<CComPtr<ID3D12CommandAllocator>> CmdAllocators; + d3d12CmdLists.reserve(NumContexts); + CmdAllocators.reserve(NumContexts); + + for (Uint32 i = 0; i < NumContexts; ++i) + { + auto& pCtx = pContexts[i]; + VERIFY_EXPR(pCtx); + CComPtr<ID3D12CommandAllocator> 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) diff --git a/Graphics/GraphicsEngineNextGenBase/include/RenderDeviceNextGenBase.hpp b/Graphics/GraphicsEngineNextGenBase/include/RenderDeviceNextGenBase.hpp index ee1fe82c..55e71a21 100644 --- a/Graphics/GraphicsEngineNextGenBase/include/RenderDeviceNextGenBase.hpp +++ b/Graphics/GraphicsEngineNextGenBase/include/RenderDeviceNextGenBase.hpp @@ -29,9 +29,9 @@ #include <vector> #include <mutex> +#include <atomic> #include "EngineFactory.h" -#include "Atomics.hpp" #include "BasicTypes.h" #include "ReferenceCounters.h" #include "MemoryAllocator.h" @@ -118,7 +118,7 @@ public: auto& Queue = m_CommandQueues[QueueIndex]; // Do not use std::move on wrapper!!! - Queue.ReleaseQueue.SafeReleaseResource(Wrapper, Queue.NextCmdBufferNumber); + Queue.ReleaseQueue.SafeReleaseResource(Wrapper, Queue.NextCmdBufferNumber.load()); QueueMask &= ~(Uint64{1} << Uint64{QueueIndex}); --NumReferences; } @@ -163,11 +163,11 @@ public: if (ReleaseResources) { - // Increment command buffer number before idling the queue. + // Increment the 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<Uint64>(Queue.NextCmdBufferNumber); - Atomics::AtomicIncrement(Queue.NextCmdBufferNumber); + CmdBufferNumber = Queue.NextCmdBufferNumber.fetch_add(1); + // fetch_add returns the original value immediately preceding the addition. } FenceValue = Queue.CmdQueue->WaitForIdle(); @@ -191,8 +191,8 @@ public: Uint64 CmdBufferNumber = 0; Uint64 FenceValue = 0; }; - template <typename SubmitDataType> - SubmittedCommandBufferInfo SubmitCommandBuffer(Uint32 QueueIndex, SubmitDataType& SubmitData, bool DiscardStaleResources) + template <typename... SubmitDataType> + SubmittedCommandBufferInfo SubmitCommandBuffer(Uint32 QueueIndex, bool DiscardStaleResources, const SubmitDataType&... SubmitData) { SubmittedCommandBufferInfo CmdBuffInfo; VERIFY_EXPR(QueueIndex < m_CmdQueueCount); @@ -201,13 +201,13 @@ public: { std::lock_guard<std::mutex> Lock{Queue.Mtx}; - // Increment command buffer number before submitting the cmd buffer. + // Increment the command buffer number before submitting the cmd buffer. // This will make sure that any resource released while this function // is running will be associated with the next command buffer. - CmdBuffInfo.CmdBufferNumber = static_cast<Uint64>(Queue.NextCmdBufferNumber); - Atomics::AtomicIncrement(Queue.NextCmdBufferNumber); + CmdBuffInfo.CmdBufferNumber = Queue.NextCmdBufferNumber.fetch_add(1); + // fetch_add returns the original value immediately preceding the addition. - CmdBuffInfo.FenceValue = Queue.CmdQueue->Submit(SubmitData); + CmdBuffInfo.FenceValue = Queue.CmdQueue->Submit(SubmitData...); } if (DiscardStaleResources) @@ -304,7 +304,7 @@ protected: CmdQueue{std::move(_CmdQueue)}, ReleaseQueue{Allocator} { - NextCmdBufferNumber = 0; + NextCmdBufferNumber.store(0); } // clang-format off @@ -315,7 +315,7 @@ protected: // clang-format on std::mutex Mtx; - Atomics::AtomicInt64 NextCmdBufferNumber; + std::atomic_uint64_t NextCmdBufferNumber{0}; RefCntAutoPtr<CommandQueueType> CmdQueue; ResourceReleaseQueue<DynamicStaleResourceWrapper> ReleaseQueue; }; diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp index fae3cba8..c59a968a 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp @@ -226,8 +226,9 @@ public: /// Implementation of IDeviceContext::FinishCommandList() in OpenGL backend. virtual void DILIGENT_CALL_TYPE FinishCommandList(class ICommandList** ppCommandList) override final; - /// Implementation of IDeviceContext::ExecuteCommandList() in OpenGL backend. - virtual void DILIGENT_CALL_TYPE ExecuteCommandList(class ICommandList* pCommandList) override final; + /// Implementation of IDeviceContext::ExecuteCommandLists() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) override final; /// Implementation of IDeviceContext::SignalFence() in OpenGL backend. virtual void DILIGENT_CALL_TYPE SignalFence(IFence* pFence, Uint64 Value) override final; diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index d5ca1766..530bc006 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -1282,7 +1282,8 @@ void DeviceContextGLImpl::FinishCommandList(class ICommandList** ppCommandList) LOG_ERROR("Deferred contexts are not supported in OpenGL mode"); } -void DeviceContextGLImpl::ExecuteCommandList(class ICommandList* pCommandList) +void DeviceContextGLImpl::ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) { LOG_ERROR("Deferred contexts are not supported in OpenGL mode"); } diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index d9a2c2f2..a385f8aa 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -233,8 +233,9 @@ public: /// Implementation of IDeviceContext::FinishCommandList() in Vulkan backend. virtual void DILIGENT_CALL_TYPE FinishCommandList(class ICommandList** ppCommandList) override final; - /// Implementation of IDeviceContext::ExecuteCommandList() in Vulkan backend. - virtual void DILIGENT_CALL_TYPE ExecuteCommandList(class ICommandList* pCommandList) override final; + /// Implementation of IDeviceContext::ExecuteCommandLists() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) override final; /// Implementation of IDeviceContext::SignalFence() in Vulkan backend. virtual void DILIGENT_CALL_TYPE SignalFence(IFence* pFence, Uint64 Value) override final; diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 37052725..60b8ebf1 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -230,12 +230,18 @@ private: virtual void TestTextureFormat(TEXTURE_FORMAT TexFormat) override final; - // Submits command buffer for execution to the command queue - // Returns the submitted command buffer number and the fence value + // Submits command buffer(s) for execution to the command queue and + // returns the submitted command buffer(s) number and the fence value. + // If SubmitInfo contains multiple command buffers, they all are treated + // like one and sumbitted atomically. // Parameters: // * SubmittedCmdBuffNumber - submitted command buffer number // * SubmittedFenceValue - fence value associated with the submitted command buffer - void SubmitCommandBuffer(Uint32 QueueIndex, const VkSubmitInfo& SubmitInfo, Uint64& SubmittedCmdBuffNumber, Uint64& SubmittedFenceValue, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pFences); + void SubmitCommandBuffer(Uint32 QueueIndex, + const VkSubmitInfo& SubmitInfo, + Uint64& SubmittedCmdBuffNumber, + Uint64& SubmittedFenceValue, + std::vector<std::pair<Uint64, RefCntAutoPtr<IFence>>>* pFences); std::shared_ptr<VulkanUtilities::VulkanInstance> m_VulkanInstance; std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> m_PhysicalDevice; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 8516a174..3259e07e 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -26,7 +26,10 @@ */ #include "pch.h" + #include <sstream> +#include <vector> + #include "RenderDeviceVkImpl.hpp" #include "DeviceContextVkImpl.hpp" #include "PipelineStateVkImpl.hpp" @@ -2098,7 +2101,8 @@ void DeviceContextVkImpl::FinishCommandList(class ICommandList** ppCommandList) InvalidateState(); } -void DeviceContextVkImpl::ExecuteCommandList(class ICommandList* pCommandList) +void DeviceContextVkImpl::ExecuteCommandLists(Uint32 NumCommandLists, + ICommandList* const* ppCommandLists) { if (m_bIsDeferred) { @@ -2106,31 +2110,50 @@ void DeviceContextVkImpl::ExecuteCommandList(class ICommandList* pCommandList) return; } + if (NumCommandLists == 0) + return; + DEV_CHECK_ERR(ppCommandLists != nullptr, "ppCommandLists must not be null when NumCommandLists is not zero"); + Flush(); InvalidateState(); - CommandListVkImpl* pCmdListVk = ValidatedCast<CommandListVkImpl>(pCommandList); - VkCommandBuffer vkCmdBuff = VK_NULL_HANDLE; + // TODO: replace with small_vector + std::vector<VkCommandBuffer> vkCmdBuffs; + std::vector<RefCntAutoPtr<IDeviceContext>> DeferredCtxs; + vkCmdBuffs.reserve(NumCommandLists); + DeferredCtxs.reserve(NumCommandLists); + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + auto* pCmdListVk = ValidatedCast<CommandListVkImpl>(ppCommandLists[i]); + DEV_CHECK_ERR(pCmdListVk != nullptr, "Command list must not be null"); + VkCommandBuffer vkCmdBuff = VK_NULL_HANDLE; + RefCntAutoPtr<IDeviceContext> pDeferredCtx; + pCmdListVk->Close(vkCmdBuff, pDeferredCtx); + VERIFY(vkCmdBuff != VK_NULL_HANDLE, "Trying to execute empty command buffer"); + VERIFY_EXPR(pDeferredCtx); + vkCmdBuffs.emplace_back(vkCmdBuff); + DeferredCtxs.emplace_back(std::move(pDeferredCtx)); + } - RefCntAutoPtr<IDeviceContext> pDeferredCtx; - pCmdListVk->Close(vkCmdBuff, pDeferredCtx); - VERIFY(vkCmdBuff != VK_NULL_HANDLE, "Trying to execute empty command buffer"); - VERIFY_EXPR(pDeferredCtx); VkSubmitInfo SubmitInfo = {}; SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; SubmitInfo.pNext = nullptr; - SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &vkCmdBuff; + SubmitInfo.commandBufferCount = NumCommandLists; + SubmitInfo.pCommandBuffers = vkCmdBuffs.data(); VERIFY_EXPR(m_PendingFences.empty()); - auto pDeferredCtxVkImpl = pDeferredCtx.RawPtr<DeviceContextVkImpl>(); auto SubmittedFenceValue = m_pDevice->ExecuteCommandBuffer(m_CommandQueueId, SubmitInfo, this, nullptr); - // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context - pDeferredCtxVkImpl->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; - // It is OK to dispose command buffer from another thread. We are not going to - // record any commands and only need to add the buffer to the queue - pDeferredCtxVkImpl->DisposeVkCmdBuffer(m_CommandQueueId, vkCmdBuff, SubmittedFenceValue); + + for (Uint32 i = 0; i < NumCommandLists; ++i) + { + auto pDeferredCtxVkImpl = DeferredCtxs[i].RawPtr<DeviceContextVkImpl>(); + // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context + pDeferredCtxVkImpl->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; + // It is OK to dispose command buffer from another thread. We are not going to + // record any commands and only need to add the buffer to the queue + pDeferredCtxVkImpl->DisposeVkCmdBuffer(m_CommandQueueId, std::move(vkCmdBuffs[i]), SubmittedFenceValue); + } } void DeviceContextVkImpl::SignalFence(IFence* pFence, Uint64 Value) diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 90c1a88e..b09d8068 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -399,7 +399,7 @@ void RenderDeviceVkImpl::SubmitCommandBuffer(Uint32 ) { // Submit the command list to the queue - auto CmbBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, SubmitInfo, true); + auto CmbBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, true, SubmitInfo); SubmittedFenceValue = CmbBuffInfo.FenceValue; SubmittedCmdBuffNumber = CmbBuffInfo.CmdBufferNumber; if (pFences != nullptr) @@ -443,7 +443,7 @@ void RenderDeviceVkImpl::FlushStaleResources(Uint32 CmdQueueIndex) // Submit empty command buffer to the queue. This will effectively signal the fence and // discard all resources VkSubmitInfo DummySumbitInfo = {}; - TRenderDeviceBase::SubmitCommandBuffer(0, DummySumbitInfo, true); + TRenderDeviceBase::SubmitCommandBuffer(0, true, DummySumbitInfo); } void RenderDeviceVkImpl::ReleaseStaleResources(bool ForceRelease) |
