Browse Source

Optimize the parallel recording of secondary command buffers

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
33df05cd21
4 changed files with 38 additions and 35 deletions
  1. 33 20
      AnKi/Gr/RenderGraph.cpp
  2. 1 1
      AnKi/Gr/RenderGraph.h
  3. 3 0
      AnKi/Renderer/LightShading.cpp
  4. 1 14
      AnKi/Renderer/MainRenderer.cpp

+ 33 - 20
AnKi/Gr/RenderGraph.cpp

@@ -14,6 +14,7 @@
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/StringList.h>
 #include <AnKi/Util/HighRezTimer.h>
+#include <AnKi/Core/Common.h>
 
 namespace anki {
 
@@ -1239,38 +1240,50 @@ AccelerationStructure* RenderGraph::getAs(AccelerationStructureHandle handle) co
 	return m_ctx->m_as[handle.m_idx].m_as.get();
 }
 
-void RenderGraph::runSecondLevel(U32 threadIdx)
+void RenderGraph::runSecondLevel()
 {
 	ANKI_TRACE_SCOPED_EVENT(GrRenderGraph2ndLevel);
 	ANKI_ASSERT(m_ctx);
 
-	RenderPassWorkContext ctx;
-	ctx.m_rgraph = this;
-	ctx.m_currentSecondLevelCommandBufferIndex = threadIdx;
+	StackMemoryPool& pool = *m_ctx->m_rts.getMemoryPool().m_pool;
 
-	for(Pass& p : m_ctx->m_passes)
+	for(Pass& pass : m_ctx->m_passes)
 	{
-		const U32 size = p.m_secondLevelCmdbs.getSize();
-		if(threadIdx < size)
+		for(U32 cmdIdx = 0; cmdIdx < pass.m_secondLevelCmdbs.getSize(); ++cmdIdx)
 		{
-			ANKI_ASSERT(!p.m_secondLevelCmdbs[threadIdx].isCreated());
-			p.m_secondLevelCmdbs[threadIdx] = GrManager::getSingleton().newCommandBuffer(p.m_secondLevelCmdbInitInfo);
+			RenderPassWorkContext* ctx = anki::newInstance<RenderPassWorkContext>(pool);
+			ctx->m_rgraph = this;
+			ctx->m_currentSecondLevelCommandBufferIndex = cmdIdx;
+			ctx->m_secondLevelCommandBufferCount = pass.m_secondLevelCmdbs.getSize();
+			ctx->m_passIdx = U32(&pass - &m_ctx->m_passes[0]);
+			ctx->m_batchIdx = pass.m_batchIdx;
+
+			auto callback = [](void* userData, [[maybe_unused]] U32 threadId, [[maybe_unused]] ThreadHive& hive,
+							   [[maybe_unused]] ThreadHiveSemaphore* signalSemaphore) {
+				RenderPassWorkContext& self = *static_cast<RenderPassWorkContext*>(userData);
+
+				ANKI_TRACE_SCOPED_EVENT(GrExecuteSecondaryCmdb);
+
+				// Create the command buffer in the thread
+				Pass& pass = self.m_rgraph->m_ctx->m_passes[self.m_passIdx];
+				ANKI_ASSERT(!pass.m_secondLevelCmdbs[self.m_currentSecondLevelCommandBufferIndex].isCreated());
+				pass.m_secondLevelCmdbs[self.m_currentSecondLevelCommandBufferIndex] =
+					GrManager::getSingleton().newCommandBuffer(pass.m_secondLevelCmdbInitInfo);
+				self.m_commandBuffer = pass.m_secondLevelCmdbs[self.m_currentSecondLevelCommandBufferIndex].get();
 
-			ctx.m_commandBuffer = p.m_secondLevelCmdbs[threadIdx].get();
-			ctx.m_secondLevelCommandBufferCount = size;
-			ctx.m_passIdx = U32(&p - &m_ctx->m_passes[0]);
-			ctx.m_batchIdx = p.m_batchIdx;
-
-			ANKI_ASSERT(ctx.m_commandBuffer);
+				{
+					ANKI_TRACE_SCOPED_EVENT(GrRenderGraphCallback);
+					pass.m_callback(self);
+				}
 
-			{
-				ANKI_TRACE_SCOPED_EVENT(GrRenderGraphCallback);
-				p.m_callback(ctx);
-			}
+				self.m_commandBuffer->flush();
+			};
 
-			ctx.m_commandBuffer->flush();
+			CoreThreadHive::getSingleton().submitTask(callback, ctx);
 		}
 	}
+
+	CoreThreadHive::getSingleton().waitAllTasks();
 }
 
 void RenderGraph::run() const

+ 1 - 1
AnKi/Gr/RenderGraph.h

@@ -637,7 +637,7 @@ public:
 	/// @{
 
 	/// Will call a number of RenderPassWorkCallback that populate 2nd level command buffers.
-	void runSecondLevel(U32 threadIdx);
+	void runSecondLevel();
 	/// @}
 
 	/// @name 3rd step methods

+ 3 - 0
AnKi/Renderer/LightShading.cpp

@@ -20,6 +20,7 @@
 #include <AnKi/Renderer/ClusterBinning.h>
 #include <AnKi/Renderer/PackVisibleClusteredObjects.h>
 #include <AnKi/Core/ConfigSet.h>
+#include <AnKi/Util/Tracer.h>
 
 namespace anki {
 
@@ -138,6 +139,8 @@ Error LightShading::initApplyIndirect()
 
 void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
 {
+	ANKI_TRACE_SCOPED_EVENT(ForwardShading);
+
 	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
 	cmdb.setViewport(0, 0, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());

+ 1 - 14
AnKi/Renderer/MainRenderer.cpp

@@ -143,20 +143,7 @@ Error MainRenderer::render(RenderQueue& rqueue, Texture* presentTex)
 	m_rgraph->compileNewGraph(ctx.m_renderGraphDescr, m_framePool);
 
 	// Populate the 2nd level command buffers
-	Array<ThreadHiveTask, ThreadHive::kMaxThreads> tasks;
-	for(U i = 0; i < CoreThreadHive::getSingleton().getThreadCount(); ++i)
-	{
-		tasks[i].m_argument = this;
-		tasks[i].m_callback = [](void* userData, [[maybe_unused]] U32 threadId, [[maybe_unused]] ThreadHive& hive,
-								 [[maybe_unused]] ThreadHiveSemaphore* signalSemaphore) {
-			MainRenderer& self = *static_cast<MainRenderer*>(userData);
-
-			const U32 taskId = self.m_runCtx.m_secondaryTaskId.fetchAdd(1);
-			self.m_rgraph->runSecondLevel(taskId);
-		};
-	}
-	CoreThreadHive::getSingleton().submitTasks(&tasks[0], CoreThreadHive::getSingleton().getThreadCount());
-	CoreThreadHive::getSingleton().waitAllTasks();
+	m_rgraph->runSecondLevel();
 
 	// Populate 1st level command buffers
 	m_rgraph->run();