Przeglądaj źródła

Fix a bug with less than 6 CPU core count

Panagiotis Christopoulos Charitos 6 lat temu
rodzic
commit
1f98cc6d10

+ 142 - 84
src/anki/renderer/GlobalIllumination.cpp

@@ -51,6 +51,9 @@ public:
 	RenderTargetHandle m_lightShadingRt;
 	WeakArray<RenderTargetHandle> m_irradianceProbeRts;
 
+	U32 m_gbufferDrawcallCount ANKI_DEBUG_CODE(= MAX_U32);
+	U32 m_smDrawcallCount ANKI_DEBUG_CODE(= MAX_U32);
+
 	static void foo()
 	{
 		static_assert(std::is_trivially_destructible<InternalContext>::value, "See file");
@@ -260,6 +263,26 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 		return;
 	}
 
+	// Compute task counts for some of the passes
+	U gbufferTaskCount, smTaskCount;
+	{
+		giCtx->m_gbufferDrawcallCount = 0;
+		giCtx->m_smDrawcallCount = 0;
+		for(const RenderQueue* rq : giCtx->m_probeToUpdateThisFrame->m_renderQueues)
+		{
+			ANKI_ASSERT(rq);
+			giCtx->m_gbufferDrawcallCount += rq->m_renderables.getSize();
+
+			if(rq->m_directionalLight.hasShadow())
+			{
+				giCtx->m_smDrawcallCount += rq->m_directionalLight.m_shadowRenderQueues[0]->m_renderables.getSize();
+			}
+		}
+
+		gbufferTaskCount = computeNumberOfSecondLevelCommandBuffers(giCtx->m_gbufferDrawcallCount);
+		smTaskCount = computeNumberOfSecondLevelCommandBuffers(giCtx->m_smDrawcallCount);
+	}
+
 	// GBuffer
 	{
 		// RTs
@@ -278,7 +301,7 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 				giCtx->m_gi->runGBufferInThread(rgraphCtx, *giCtx);
 			},
 			giCtx,
-			6);
+			gbufferTaskCount);
 
 		for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
 		{
@@ -338,7 +361,7 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 				giCtx->m_gi->runShadowmappingInThread(rgraphCtx, *giCtx);
 			},
 			giCtx,
-			6);
+			smTaskCount);
 
 		TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
 		pass.newDependency({giCtx->m_shadowsRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, subresource});
@@ -362,7 +385,7 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 				giCtx->m_gi->runLightShading(rgraphCtx, *giCtx);
 			},
 			giCtx,
-			6);
+			1);
 
 		pass.newDependency({giCtx->m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
 
@@ -576,67 +599,97 @@ void GlobalIllumination::runGBufferInThread(RenderPassWorkContext& rgraphCtx, In
 	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
-	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
-	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
-	ANKI_ASSERT(faceIdx < 6);
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
 
-	const U32 viewportX = faceIdx * m_tileSize;
-	cmdb->setViewport(viewportX, 0, m_tileSize, m_tileSize);
-	cmdb->setScissor(viewportX, 0, m_tileSize, m_tileSize);
-
-	/// Draw
-	ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
-	const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
+	I start, end;
+	splitThreadedProblem(rgraphCtx.m_currentSecondLevelCommandBufferIndex,
+		rgraphCtx.m_secondLevelCommandBufferCount,
+		giCtx.m_gbufferDrawcallCount,
+		start,
+		end);
 
-	if(!rqueue.m_renderables.isEmpty())
+	I drawcallCount = 0;
+	for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 	{
-		m_r->getSceneDrawer().drawRange(Pass::GB,
-			rqueue.m_viewMatrix,
-			rqueue.m_viewProjectionMatrix,
-			Mat4::getIdentity(), // Don't care about prev mats since we don't care about velocity
-			cmdb,
-			m_r->getSamplers().m_trilinearRepeat,
-			rqueue.m_renderables.getBegin(),
-			rqueue.m_renderables.getEnd(),
-			MAX_LOD_COUNT - 1);
+		const I faceDrawcallCount = I(probe.m_renderQueues[faceIdx]->m_renderables.getSize());
+		const I localStart = max(I(0), start - drawcallCount);
+		const I localEnd = min(faceDrawcallCount, end - drawcallCount);
+
+		if(localStart < localEnd)
+		{
+			const U32 viewportX = faceIdx * m_tileSize;
+			cmdb->setViewport(viewportX, 0, m_tileSize, m_tileSize);
+			cmdb->setScissor(viewportX, 0, m_tileSize, m_tileSize);
+
+			const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
+
+			ANKI_ASSERT(localStart >= 0 && localEnd <= faceDrawcallCount);
+			m_r->getSceneDrawer().drawRange(Pass::GB,
+				rqueue.m_viewMatrix,
+				rqueue.m_viewProjectionMatrix,
+				Mat4::getIdentity(), // Don't care about prev mats since we don't care about velocity
+				cmdb,
+				m_r->getSamplers().m_trilinearRepeat,
+				rqueue.m_renderables.getBegin() + localStart,
+				rqueue.m_renderables.getBegin() + localEnd,
+				MAX_LOD_COUNT - 1);
+		}
+
+		drawcallCount += faceDrawcallCount;
 	}
+	ANKI_ASSERT(giCtx.m_gbufferDrawcallCount == drawcallCount);
 
 	// It's secondary, no need to restore the state
 }
 
 void GlobalIllumination::runShadowmappingInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
 {
-	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
-	ANKI_ASSERT(faceIdx < 6);
+	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
+	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	cmdb->setPolygonOffset(1.0f, 1.0f);
+	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
 
-	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
-	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame->m_renderQueues[faceIdx]);
-	const RenderQueue& faceRenderQueue = *giCtx.m_probeToUpdateThisFrame->m_renderQueues[faceIdx];
-	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_uuid != 0);
-	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowCascadeCount == 1);
+	I start, end;
+	splitThreadedProblem(rgraphCtx.m_currentSecondLevelCommandBufferIndex,
+		rgraphCtx.m_secondLevelCommandBufferCount,
+		giCtx.m_smDrawcallCount,
+		start,
+		end);
 
-	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0]);
-	const RenderQueue& cascadeRenderQueue = *faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0];
+	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	cmdb->setPolygonOffset(1.0f, 1.0f);
 
-	if(cascadeRenderQueue.m_renderables.getSize() != 0)
+	I drawcallCount = 0;
+	for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 	{
-		const U rez = m_shadowMapping.m_rtDescr.m_height;
-		cmdb->setViewport(rez * faceIdx, 0, rez, rez);
-		cmdb->setScissor(rez * faceIdx, 0, rez, rez);
+		ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
+		const RenderQueue& faceRenderQueue = *probe.m_renderQueues[faceIdx];
+		ANKI_ASSERT(faceRenderQueue.m_directionalLight.hasShadow());
+		ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0]);
+		const RenderQueue& cascadeRenderQueue = *faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0];
 
-		m_r->getSceneDrawer().drawRange(Pass::SM,
-			cascadeRenderQueue.m_viewMatrix,
-			cascadeRenderQueue.m_viewProjectionMatrix,
-			Mat4::getIdentity(), // Don't care about prev matrices here
-			cmdb,
-			m_r->getSamplers().m_trilinearRepeatAniso,
-			cascadeRenderQueue.m_renderables.getBegin(),
-			cascadeRenderQueue.m_renderables.getEnd(),
-			MAX_LOD_COUNT - 1);
+		const I faceDrawcallCount = I(cascadeRenderQueue.m_renderables.getSize());
+		const I localStart = max(I(0), start - drawcallCount);
+		const I localEnd = min(faceDrawcallCount, end - drawcallCount);
+
+		if(localStart < localEnd)
+		{
+			const U rez = m_shadowMapping.m_rtDescr.m_height;
+			cmdb->setViewport(rez * faceIdx, 0, rez, rez);
+			cmdb->setScissor(rez * faceIdx, 0, rez, rez);
+
+			ANKI_ASSERT(localStart >= 0 && localEnd <= faceDrawcallCount);
+			m_r->getSceneDrawer().drawRange(Pass::SM,
+				cascadeRenderQueue.m_viewMatrix,
+				cascadeRenderQueue.m_viewProjectionMatrix,
+				Mat4::getIdentity(), // Don't care about prev matrices here
+				cmdb,
+				m_r->getSamplers().m_trilinearRepeatAniso,
+				cascadeRenderQueue.m_renderables.getBegin() + localStart,
+				cascadeRenderQueue.m_renderables.getBegin() + localEnd,
+				MAX_LOD_COUNT - 1);
+		}
 	}
 
 	// It's secondary, no need to restore the state
@@ -646,55 +699,60 @@ void GlobalIllumination::runLightShading(RenderPassWorkContext& rgraphCtx, Inter
 {
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
-	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
-	ANKI_ASSERT(faceIdx < 6);
 
-	ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
-	const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
+	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	// Set common state for all lights
+	{
+		// NOTE: Use nearest sampler because we don't want the result to sample the near tiles
+		cmdb->bindSampler(0, 2, m_r->getSamplers().m_nearestNearestClamp);
+
+		rgraphCtx.bindColorTexture(0, 3, giCtx.m_gbufferColorRts[0]);
+		rgraphCtx.bindColorTexture(0, 4, giCtx.m_gbufferColorRts[1]);
+		rgraphCtx.bindColorTexture(0, 5, giCtx.m_gbufferColorRts[2]);
 
-	const U rez = m_tileSize;
-	cmdb->setScissor(rez * faceIdx, 0, rez, rez);
+		rgraphCtx.bindTexture(0, 6, giCtx.m_gbufferDepthRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
 
-	// Set common state for all lights
-	// NOTE: Use nearest sampler because we don't want the result to sample the near tiles
-	cmdb->bindSampler(0, 2, m_r->getSamplers().m_nearestNearestClamp);
+		// Get shadowmap info
+		if(probe.m_renderQueues[0]->m_directionalLight.isEnabled())
+		{
+			ANKI_ASSERT(giCtx.m_shadowsRt.isValid());
 
-	rgraphCtx.bindColorTexture(0, 3, giCtx.m_gbufferColorRts[0]);
-	rgraphCtx.bindColorTexture(0, 4, giCtx.m_gbufferColorRts[1]);
-	rgraphCtx.bindColorTexture(0, 5, giCtx.m_gbufferColorRts[2]);
+			cmdb->bindSampler(0, 7, m_shadowMapping.m_shadowSampler);
 
-	rgraphCtx.bindTexture(0, 6, giCtx.m_gbufferDepthRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
+			rgraphCtx.bindTexture(0, 8, giCtx.m_shadowsRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
+		}
+	}
 
-	// Get shadowmap info
-	const Bool hasDirLight = probe.m_renderQueues[0]->m_directionalLight.m_uuid;
-	if(hasDirLight)
+	for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 	{
-		ANKI_ASSERT(giCtx.m_shadowsRt.isValid());
+		ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
+		const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
 
-		cmdb->bindSampler(0, 7, m_shadowMapping.m_shadowSampler);
+		const U rez = m_tileSize;
+		cmdb->setScissor(rez * faceIdx, 0, rez, rez);
+		cmdb->setViewport(rez * faceIdx, 0, rez, rez);
 
-		rgraphCtx.bindTexture(0, 8, giCtx.m_shadowsRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
+		TraditionalDeferredLightShadingDrawInfo dsInfo;
+		dsInfo.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
+		dsInfo.m_invViewProjectionMatrix = rqueue.m_viewProjectionMatrix.getInverse();
+		dsInfo.m_cameraPosWSpace = rqueue.m_cameraTransform.getTranslationPart();
+		dsInfo.m_viewport = UVec4(faceIdx * m_tileSize, 0, m_tileSize, m_tileSize);
+		dsInfo.m_gbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize * 6), 1.0f / F32(m_tileSize));
+		dsInfo.m_gbufferTexCoordsBias = Vec2(0.0f, 0.0f);
+		dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize), 1.0f / F32(m_tileSize));
+		dsInfo.m_lightbufferTexCoordsBias = Vec2(-F32(faceIdx), 0.0f);
+		dsInfo.m_cameraNear = probe.m_renderQueues[faceIdx]->m_cameraNear;
+		dsInfo.m_cameraFar = probe.m_renderQueues[faceIdx]->m_cameraFar;
+		dsInfo.m_directionalLight = (probe.m_renderQueues[faceIdx]->m_directionalLight.isEnabled())
+										? &probe.m_renderQueues[faceIdx]->m_directionalLight
+										: nullptr;
+		dsInfo.m_pointLights = rqueue.m_pointLights;
+		dsInfo.m_spotLights = rqueue.m_spotLights;
+		dsInfo.m_commandBuffer = cmdb;
+		m_lightShading.m_deferred.drawLights(dsInfo);
 	}
-
-	TraditionalDeferredLightShadingDrawInfo dsInfo;
-	dsInfo.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
-	dsInfo.m_invViewProjectionMatrix = rqueue.m_viewProjectionMatrix.getInverse();
-	dsInfo.m_cameraPosWSpace = rqueue.m_cameraTransform.getTranslationPart();
-	dsInfo.m_viewport = UVec4(faceIdx * m_tileSize, 0, m_tileSize, m_tileSize);
-	dsInfo.m_gbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize * 6), 1.0f / F32(m_tileSize));
-	dsInfo.m_gbufferTexCoordsBias = Vec2(0.0f, 0.0f);
-	dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize), 1.0f / F32(m_tileSize));
-	dsInfo.m_lightbufferTexCoordsBias = Vec2(-F32(faceIdx), 0.0f);
-	dsInfo.m_cameraNear = probe.m_renderQueues[faceIdx]->m_cameraNear;
-	dsInfo.m_cameraFar = probe.m_renderQueues[faceIdx]->m_cameraFar;
-	dsInfo.m_directionalLight = (hasDirLight) ? &probe.m_renderQueues[faceIdx]->m_directionalLight : nullptr;
-	dsInfo.m_pointLights = rqueue.m_pointLights;
-	dsInfo.m_spotLights = rqueue.m_spotLights;
-	dsInfo.m_commandBuffer = cmdb;
-	m_lightShading.m_deferred.drawLights(dsInfo);
 }
 
 void GlobalIllumination::runIrradiance(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)

+ 10 - 0
src/anki/renderer/RenderQueue.h

@@ -169,6 +169,16 @@ public:
 	DirectionalLightQueueElement()
 	{
 	}
+
+	ANKI_USE_RESULT Bool isEnabled() const
+	{
+		return m_uuid != 0;
+	}
+
+	ANKI_USE_RESULT Bool hasShadow() const
+	{
+		return isEnabled() && m_shadowCascadeCount > 0;
+	}
 };
 
 static_assert(