summaryrefslogtreecommitdiffstats
path: root/Graphics
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2021-02-07 20:50:39 +0000
committerassiduous <assiduous@diligentgraphics.com>2021-02-07 20:50:39 +0000
commitc6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c (patch)
treee8848a7e01b2f576c11e9f9acfee6eca9fcdd681 /Graphics
parentSwap chain Vk: improved presentation mode selection (fixed https://github.com... (diff)
downloadDiligentCore-c6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c.tar.gz
DiligentCore-c6c5bb5ed3d4e3296e6f65e4072db5cf8bf2452c.zip
Reworked ExecuteCommandList(s) to take multiple command lists instead of one
Diffstat (limited to 'Graphics')
-rw-r--r--Graphics/GraphicsEngine/interface/APIInfo.h2
-rw-r--r--Graphics/GraphicsEngine/interface/DeviceContext.h14
-rw-r--r--Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp5
-rwxr-xr-xGraphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp30
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandQueueD3D12Impl.hpp3
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp5
-rw-r--r--Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp9
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/CommandQueueD3D12.h11
-rw-r--r--Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp16
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp40
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp46
-rw-r--r--Graphics/GraphicsEngineNextGenBase/include/RenderDeviceNextGenBase.hpp26
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp5
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp3
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp5
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp12
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp53
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp4
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)