Browse Source

Move GI probes fully to the GPU occlusion system

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
a3a8a96180

+ 1 - 1
AnKi/Gr/RenderGraph.h

@@ -31,7 +31,7 @@ class RenderGraphDescription;
 /// @{
 /// @{
 constexpr U32 kMaxRenderGraphPasses = 256;
 constexpr U32 kMaxRenderGraphPasses = 256;
 constexpr U32 kMaxRenderGraphRenderTargets = 64; ///< Max imported or not render targets in RenderGraph.
 constexpr U32 kMaxRenderGraphRenderTargets = 64; ///< Max imported or not render targets in RenderGraph.
-constexpr U32 kMaxRenderGraphBuffers = 128;
+constexpr U32 kMaxRenderGraphBuffers = 256;
 constexpr U32 kMaxRenderGraphAccelerationStructures = 32;
 constexpr U32 kMaxRenderGraphAccelerationStructures = 32;
 /// @}
 /// @}
 
 

+ 13 - 1
AnKi/Renderer/ClusterBinning2.cpp

@@ -150,8 +150,14 @@ void ClusterBinning2::populateRenderGraph(RenderingContext& ctx)
 				default:
 				default:
 					ANKI_ASSERT(0);
 					ANKI_ASSERT(0);
 				}
 				}
-				cmdb.bindStorageBuffer(0, 1, &GpuSceneBuffer::getSingleton().getBuffer(), objBufferOffset, objBufferRange);
 
 
+				if(objBufferRange == 0)
+				{
+					objBufferOffset = 0;
+					objBufferRange = kMaxPtrSize;
+				}
+
+				cmdb.bindStorageBuffer(0, 1, &GpuSceneBuffer::getSingleton().getBuffer(), objBufferOffset, objBufferRange);
 				cmdb.bindStorageBuffer(0, 2, m_runCtx.m_clustersBuffer.m_buffer, m_runCtx.m_clustersBuffer.m_offset,
 				cmdb.bindStorageBuffer(0, 2, m_runCtx.m_clustersBuffer.m_buffer, m_runCtx.m_clustersBuffer.m_offset,
 									   m_runCtx.m_clustersBuffer.m_range);
 									   m_runCtx.m_clustersBuffer.m_range);
 
 
@@ -246,6 +252,12 @@ void ClusterBinning2::populateRenderGraph(RenderingContext& ctx)
 					ANKI_ASSERT(0);
 					ANKI_ASSERT(0);
 				}
 				}
 
 
+				if(objBufferRange == 0)
+				{
+					objBufferOffset = 0;
+					objBufferRange = kMaxPtrSize;
+				}
+
 				cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), objBufferOffset, objBufferRange);
 				cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), objBufferOffset, objBufferRange);
 				cmdb.bindStorageBuffer(0, 1, m_runCtx.m_packedObjectsBuffers[type].m_buffer, m_runCtx.m_packedObjectsBuffers[type].m_offset,
 				cmdb.bindStorageBuffer(0, 1, m_runCtx.m_packedObjectsBuffers[type].m_buffer, m_runCtx.m_packedObjectsBuffers[type].m_offset,
 									   m_runCtx.m_packedObjectsBuffers[type].m_range);
 									   m_runCtx.m_packedObjectsBuffers[type].m_range);

+ 309 - 322
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -6,10 +6,16 @@
 #include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/RenderQueue.h>
+#include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
+#include <AnKi/Scene/SceneGraph.h>
+#include <AnKi/Scene/Components/GlobalIlluminationProbeComponent.h>
+#include <AnKi/Scene/Components/LightComponent.h>
 #include <AnKi/Core/CVarSet.h>
 #include <AnKi/Core/CVarSet.h>
+#include <AnKi/Core/StatsSet.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Collision/Aabb.h>
 #include <AnKi/Collision/Aabb.h>
 #include <AnKi/Collision/Functions.h>
 #include <AnKi/Collision/Functions.h>
+#include <AnKi/Resource/AsyncLoader.h>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -18,38 +24,21 @@ static NumericCVar<U32> g_indirectDiffuseProbeTileResolutionCVar(CVarSubsystem::
 static NumericCVar<U32> g_indirectDiffuseProbeShadowMapResolutionCVar(CVarSubsystem::kRenderer, "IndirectDiffuseProbeShadowMapResolution", 128, 4,
 static NumericCVar<U32> g_indirectDiffuseProbeShadowMapResolutionCVar(CVarSubsystem::kRenderer, "IndirectDiffuseProbeShadowMapResolution", 128, 4,
 																	  2048, "GI shadowmap resolution");
 																	  2048, "GI shadowmap resolution");
 
 
-class IndirectDiffuseProbes::InternalContext
-{
-public:
-	IndirectDiffuseProbes* m_gi = nullptr;
-	RenderingContext* m_ctx = nullptr;
-
-	GlobalIlluminationProbeQueueElementForRefresh* m_probeToUpdateThisFrame = nullptr;
-
-	Array<RenderTargetHandle, kGBufferColorRenderTargetCount> m_gbufferColorRts;
-	RenderTargetHandle m_gbufferDepthRt;
-	RenderTargetHandle m_shadowsRt;
-	RenderTargetHandle m_lightShadingRt;
-	RenderTargetHandle m_irradianceVolume;
-
-	Array<GpuVisibilityOutput, 6> m_gbufferVisOut;
-	Array<GpuVisibilityOutput, 6> m_shadowsVisOut;
-
-	static void foo()
-	{
-		static_assert(std::is_trivially_destructible<InternalContext>::value, "See file");
-	}
-};
-
-RenderTargetHandle IndirectDiffuseProbes::getCurrentlyRefreshedVolumeRt() const
-{
-	ANKI_ASSERT(m_giCtx && m_giCtx->m_irradianceVolume.isValid());
-	return m_giCtx->m_irradianceVolume;
-}
+static StatCounter g_giProbeRenderCountStatVar(StatCategory::kMisc, "GI probes rendered");
+static StatCounter g_giProbeCellsRenderCountStatVar(StatCategory::kMisc, "GI probes cells rendered");
 
 
-Bool IndirectDiffuseProbes::hasCurrentlyRefreshedVolumeRt() const
+static Vec3 computeCellCenter(U32 cellIdx, const GlobalIlluminationProbeComponent& probe)
 {
 {
-	return m_giCtx != nullptr;
+	const Vec3 halfAabbSize = probe.getBoxVolumeSize() / 2.0f;
+	const Vec3 aabbMin = -halfAabbSize + probe.getWorldPosition();
+	U32 x, y, z;
+	unflatten3dArrayIndex(probe.getCellCountsPerDimension().x(), probe.getCellCountsPerDimension().y(), probe.getCellCountsPerDimension().z(),
+						  cellIdx, x, y, z);
+	const Vec3 cellSize = probe.getBoxVolumeSize() / Vec3(probe.getCellCountsPerDimension());
+	const Vec3 halfCellSize = cellSize / 2.0f;
+	const Vec3 cellCenter = aabbMin + halfCellSize + cellSize * Vec3(UVec3(x, y, z));
+
+	return cellCenter;
 }
 }
 
 
 Error IndirectDiffuseProbes::init()
 Error IndirectDiffuseProbes::init()
@@ -179,356 +168,354 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
 	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
 
 
-	if(rctx.m_renderQueue->m_giProbeForRefresh == nullptr) [[likely]]
+	// Iterate the visible probes to find a candidate for update
+	WeakArray<GlobalIlluminationProbeComponent*> visibleProbes =
+		getRenderer().getPrimaryNonRenderableVisibility().getInterestingVisibleComponents().m_globalIlluminationProbes;
+	GlobalIlluminationProbeComponent* bestCandidateProbe = nullptr;
+	GlobalIlluminationProbeComponent* secondBestCandidateProbe = nullptr;
+	for(GlobalIlluminationProbeComponent* probe : visibleProbes)
 	{
 	{
-		m_giCtx = nullptr;
-		return;
+		if(probe->getCellsNeedsRefresh())
+		{
+			if(probe->getNextCellForRefresh() != 0)
+			{
+				bestCandidateProbe = probe;
+				break;
+			}
+			else
+			{
+				secondBestCandidateProbe = probe;
+			}
+		}
 	}
 	}
 
 
-	InternalContext* giCtx = newInstance<InternalContext>(*rctx.m_tempPool);
-	m_giCtx = giCtx;
-	giCtx->m_gi = this;
-	giCtx->m_ctx = &rctx;
-	giCtx->m_probeToUpdateThisFrame = rctx.m_renderQueue->m_giProbeForRefresh;
-	RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
-
-	// GBuffer visibility
-	for(U32 i = 0; i < 6; ++i)
+	GlobalIlluminationProbeComponent* probeToRefresh = (bestCandidateProbe) ? bestCandidateProbe : secondBestCandidateProbe;
+	if(probeToRefresh == nullptr || ResourceManager::getSingleton().getAsyncLoader().getTasksInFlightCount() != 0) [[likely]]
 	{
 	{
-		const RenderQueue& queue = *giCtx->m_probeToUpdateThisFrame->m_renderQueues[i];
-		Array<F32, kMaxLodCount - 1> lodDistances = {1000.0f, 1001.0f}; // Something far to force detailed LODs
-
-		GpuVisibilityInput visIn;
-		visIn.m_passesName = "GI GBuffer visibility";
-		visIn.m_technique = RenderingTechnique::kGBuffer;
-		visIn.m_viewProjectionMatrix = queue.m_viewProjectionMatrix;
-		visIn.m_lodReferencePoint = queue.m_cameraTransform.getTranslationPart().xyz();
-		visIn.m_lodDistances = lodDistances;
-		visIn.m_rgraph = &rgraph;
-
-		getRenderer().getGpuVisibility().populateRenderGraph(visIn, giCtx->m_gbufferVisOut[i]);
+		// Nothing to update or can't update right now, early exit
+		m_runCtx = {};
+		return;
 	}
 	}
 
 
-	// GBuffer
+	const Bool probeTouchedFirstTime = probeToRefresh->getNextCellForRefresh() == 0;
+	if(probeTouchedFirstTime)
 	{
 	{
-		// RTs
-		for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
-		{
-			giCtx->m_gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
-		}
-		giCtx->m_gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
-
-		// Pass
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI GBuffer");
-		pass.setFramebufferInfo(m_gbuffer.m_fbDescr, giCtx->m_gbufferColorRts, giCtx->m_gbufferDepthRt);
-		pass.setWork(6, [this](RenderPassWorkContext& rgraphCtx) {
-			runGBufferInThread(rgraphCtx);
-		});
+		g_giProbeRenderCountStatVar.increment(1);
+	}
 
 
-		for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
-		{
-			pass.newTextureDependency(giCtx->m_gbufferColorRts[i], TextureUsageBit::kFramebufferWrite);
-		}
+	RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
 
 
-		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
-		pass.newTextureDependency(giCtx->m_gbufferDepthRt, TextureUsageBit::kAllFramebuffer, subresource);
+	// Create some common resources to save on memory
+	Array<RenderTargetHandle, kMaxColorRenderTargets> gbufferColorRts;
+	for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+	{
+		gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
+	}
+	const RenderTargetHandle gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
 
 
-		pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(),
-								 BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
+	const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
+	const Bool doShadows = dirLightc && dirLightc->getShadowEnabled();
+	const RenderTargetHandle shadowsRt = (doShadows) ? rgraph.newRenderTarget(m_shadowMapping.m_rtDescr) : RenderTargetHandle();
+	const RenderTargetHandle lightShadingRt = rgraph.newRenderTarget(m_lightShading.m_rtDescr);
+	const RenderTargetHandle irradianceVolume = rgraph.importRenderTarget(&probeToRefresh->getVolumeTexture(), TextureUsageBit::kNone);
 
 
-		for(U32 i = 0; i < 6; ++i)
-		{
-			pass.newBufferDependency(giCtx->m_gbufferVisOut[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
-		}
-	}
+	m_runCtx.m_probeVolumeHandle = irradianceVolume;
 
 
-	// Shadow visibility. Optional
-	const Bool hasShadows = giCtx->m_probeToUpdateThisFrame->m_renderQueues[0]->m_directionalLight.m_uuid
-							&& giCtx->m_probeToUpdateThisFrame->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0;
-	if(hasShadows)
+	const U32 beginCellIdx = probeToRefresh->getNextCellForRefresh();
+	for(U32 cellIdx = beginCellIdx; cellIdx < min(beginCellIdx + kProbeCellRefreshesPerFrame, probeToRefresh->getCellCount()); ++cellIdx)
 	{
 	{
+		const Vec3 cellCenter = computeCellCenter(cellIdx, *probeToRefresh);
+
+		// GBuffer visibility
+		Array<GpuVisibilityOutput, 6> visOuts;
+		Array<Frustum, 6> frustums;
 		for(U32 i = 0; i < 6; ++i)
 		for(U32 i = 0; i < 6; ++i)
 		{
 		{
-			const RenderQueue& queue = *giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_shadowRenderQueues[0];
+			Frustum& frustum = frustums[i];
+			frustum.setPerspective(kClusterObjectFrustumNearPlane, probeToRefresh->getRenderRadius(), kPi / 2.0f, kPi / 2.0f);
+			frustum.setWorldTransform(Transform(cellCenter.xyz0(), Frustum::getOmnidirectionalFrustumRotations()[i], 1.0f));
+			frustum.update();
+
 			Array<F32, kMaxLodCount - 1> lodDistances = {1000.0f, 1001.0f}; // Something far to force detailed LODs
 			Array<F32, kMaxLodCount - 1> lodDistances = {1000.0f, 1001.0f}; // Something far to force detailed LODs
 
 
 			GpuVisibilityInput visIn;
 			GpuVisibilityInput visIn;
-			visIn.m_passesName = "GI shadows visibility";
-			visIn.m_technique = RenderingTechnique::kDepth;
-			visIn.m_viewProjectionMatrix = queue.m_viewProjectionMatrix;
-			visIn.m_lodReferencePoint = queue.m_cameraTransform.getTranslationPart().xyz();
+			visIn.m_passesName = "GI GBuffer visibility";
+			visIn.m_technique = RenderingTechnique::kGBuffer;
+			visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
+			visIn.m_lodReferencePoint = cellCenter;
 			visIn.m_lodDistances = lodDistances;
 			visIn.m_lodDistances = lodDistances;
 			visIn.m_rgraph = &rgraph;
 			visIn.m_rgraph = &rgraph;
 
 
-			getRenderer().getGpuVisibility().populateRenderGraph(visIn, giCtx->m_shadowsVisOut[i]);
+			getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOuts[i]);
 		}
 		}
-	}
 
 
-	// Shadow pass. Optional
-	if(hasShadows)
-	{
-		// Update light matrices
-		for(U i = 0; i < 6; ++i)
+		// GBuffer
+		Array<Mat4, 6> viewProjMats;
+		Array<Mat3x4, 6> viewMats;
 		{
 		{
-			ANKI_ASSERT(giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_uuid
-						&& giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount == 1);
-
-			const F32 xScale = 1.0f / 6.0f;
-			const F32 yScale = 1.0f;
-			const F32 xOffset = F32(i) * (1.0f / 6.0f);
-			const F32 yOffset = 0.0f;
-			const Mat4 atlasMtx(xScale, 0.0f, 0.0f, xOffset, 0.0f, yScale, 0.0f, yOffset, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+			// Prepare the matrices
+			for(U32 f = 0; f < 6; ++f)
+			{
+				viewProjMats[f] = frustums[f].getViewProjectionMatrix();
+				viewMats[f] = frustums[f].getViewMatrix();
+			}
+
+			// Create the pass
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI GBuffer");
+			pass.setFramebufferInfo(m_gbuffer.m_fbDescr, gbufferColorRts, gbufferDepthRt);
+
+			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+			{
+				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kFramebufferWrite);
+			}
+			pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+
+			for(U32 i = 0; i < 6; ++i)
+			{
+				pass.newBufferDependency(visOuts[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
+			}
+
+			pass.setWork(6, [this, visOuts, viewProjMats, viewMats](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+				const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
+
+				const U32 viewportX = faceIdx * m_tileSize;
+				cmdb.setViewport(viewportX, 0, m_tileSize, m_tileSize);
+				cmdb.setScissor(viewportX, 0, m_tileSize, m_tileSize);
+
+				RenderableDrawerArguments args;
+				args.m_viewMatrix = viewMats[faceIdx];
+				args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
+				args.m_viewProjectionMatrix = viewProjMats[faceIdx];
+				args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
+				args.m_renderingTechinuqe = RenderingTechnique::kGBuffer;
+				args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
+				args.fillMdi(visOuts[faceIdx]);
+
+				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+
+				// It's secondary, no need to restore any state
+			});
+		}
 
 
-			Mat4& lightMat = giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
-			lightMat = atlasMtx * lightMat;
+		// Shadow visibility. Optional
+		Array<GpuVisibilityOutput, 6> shadowVisOuts;
+		Array<Mat4, 6> cascadeViewProjMats;
+		Array<Mat3x4, 6> cascadeViewMats;
+		if(doShadows)
+		{
+			for(U32 i = 0; i < 6; ++i)
+			{
+				constexpr U32 kCascadeCount = 1;
+				dirLightc->computeCascadeFrustums(frustums[i], Array<F32, kCascadeCount>{probeToRefresh->getShadowsRenderRadius()},
+												  WeakArray<Mat4>(&cascadeViewProjMats[i], kCascadeCount),
+												  WeakArray<Mat3x4>(&cascadeViewMats[i], kCascadeCount));
+
+				Array<F32, kMaxLodCount - 1> lodDistances = {1000.0f, 1001.0f}; // Something far to force detailed LODs
+
+				GpuVisibilityInput visIn;
+				visIn.m_passesName = "GI shadows visibility";
+				visIn.m_technique = RenderingTechnique::kDepth;
+				visIn.m_viewProjectionMatrix = cascadeViewProjMats[i];
+				visIn.m_lodReferencePoint = cellCenter;
+				visIn.m_lodDistances = lodDistances;
+				visIn.m_rgraph = &rgraph;
+
+				getRenderer().getGpuVisibility().populateRenderGraph(visIn, shadowVisOuts[i]);
+			}
+		}
+		else
+		{
+			zeroMemory(cascadeViewProjMats);
+			zeroMemory(cascadeViewMats);
 		}
 		}
 
 
-		// RT
-		giCtx->m_shadowsRt = rgraph.newRenderTarget(m_shadowMapping.m_rtDescr);
+		// Shadow pass. Optional
+		if(doShadows)
+		{
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI shadows");
+			pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, shadowsRt);
 
 
-		// Pass
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI shadows");
-		pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, giCtx->m_shadowsRt);
-		pass.setWork(6, [this](RenderPassWorkContext& rgraphCtx) {
-			runShadowmappingInThread(rgraphCtx);
-		});
+			pass.newTextureDependency(shadowsRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+			for(U32 i = 0; i < 6; ++i)
+			{
+				pass.newBufferDependency(shadowVisOuts[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
+			}
 
 
-		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
-		pass.newTextureDependency(giCtx->m_shadowsRt, TextureUsageBit::kAllFramebuffer, subresource);
+			pass.setWork(6, [this, shadowVisOuts, cascadeViewProjMats, cascadeViewMats](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
 
-		pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(),
-								 BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
+				cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
 
 
-		for(U32 i = 0; i < 6; ++i)
-		{
-			pass.newBufferDependency(giCtx->m_shadowsVisOut[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
-		}
-	}
-	else
-	{
-		giCtx->m_shadowsRt = {};
-	}
+				const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
 
 
-	// Light visibility
-	Array<GpuVisibilityNonRenderablesOutput, 6> lightVis;
-	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-	{
-		GpuVisibilityNonRenderablesInput in;
-		in.m_passesName = "GI light visibility";
-		in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
-		in.m_viewProjectionMat = giCtx->m_probeToUpdateThisFrame->m_renderQueues[faceIdx]->m_viewProjectionMatrix;
-		in.m_rgraph = &rgraph;
-		getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
-	}
+				const U32 rez = m_shadowMapping.m_rtDescr.m_height;
+				cmdb.setViewport(rez * faceIdx, 0, rez, rez);
+				cmdb.setScissor(rez * faceIdx, 0, rez, rez);
 
 
-	// Light shading pass
-	{
-		// RT
-		giCtx->m_lightShadingRt = rgraph.newRenderTarget(m_lightShading.m_rtDescr);
+				RenderableDrawerArguments args;
+				args.m_viewMatrix = cascadeViewMats[faceIdx];
+				args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
+				args.m_viewProjectionMatrix = cascadeViewProjMats[faceIdx];
+				args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
+				args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
+				args.m_renderingTechinuqe = RenderingTechnique::kDepth;
+				args.fillMdi(shadowVisOuts[faceIdx]);
 
 
-		// Pass
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI light shading");
+				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
 
 
-		Array<BufferOffsetRange, 6> visibleLightsBuffers;
-		for(U32 f = 0; f < 6; ++f)
-		{
-			visibleLightsBuffers[f] = lightVis[f].m_visiblesBuffer;
-			pass.newBufferDependency(lightVis[f].m_visiblesBufferHandle, BufferUsageBit::kStorageFragmentRead);
+				// It's secondary, no need to restore the state
+			});
 		}
 		}
 
 
-		pass.setFramebufferInfo(m_lightShading.m_fbDescr, {giCtx->m_lightShadingRt});
-		pass.setWork(1, [this, visibleLightsBuffers](RenderPassWorkContext& rgraphCtx) {
-			runLightShading(visibleLightsBuffers, rgraphCtx);
-		});
-
-		pass.newTextureDependency(giCtx->m_lightShadingRt, TextureUsageBit::kFramebufferWrite);
-
-		for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+		// Light visibility
+		Array<GpuVisibilityNonRenderablesOutput, 6> lightVis;
+		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
 		{
-			pass.newTextureDependency(giCtx->m_gbufferColorRts[i], TextureUsageBit::kSampledFragment);
+			GpuVisibilityNonRenderablesInput in;
+			in.m_passesName = "GI light visibility";
+			in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
+			in.m_viewProjectionMat = cascadeViewProjMats[faceIdx];
+			in.m_rgraph = &rgraph;
+			getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
 		}
 		}
-		pass.newTextureDependency(giCtx->m_gbufferDepthRt, TextureUsageBit::kSampledFragment, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
 
-		if(giCtx->m_shadowsRt.isValid())
+		// Light shading pass
 		{
 		{
-			pass.newTextureDependency(giCtx->m_shadowsRt, TextureUsageBit::kSampledFragment);
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI light shading");
+			pass.setFramebufferInfo(m_lightShading.m_fbDescr, {lightShadingRt});
+
+			Array<BufferOffsetRange, 6> visibleLightsBuffers;
+			for(U32 f = 0; f < 6; ++f)
+			{
+				visibleLightsBuffers[f] = lightVis[f].m_visiblesBuffer;
+				pass.newBufferDependency(lightVis[f].m_visiblesBufferHandle, BufferUsageBit::kStorageFragmentRead);
+			}
+
+			pass.newTextureDependency(lightShadingRt, TextureUsageBit::kFramebufferWrite);
+
+			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+			{
+				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSampledFragment);
+			}
+			pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kSampledFragment, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+
+			if(shadowsRt.isValid())
+			{
+				pass.newTextureDependency(shadowsRt, TextureUsageBit::kSampledFragment);
+			}
+
+			pass.setWork(1, [this, visibleLightsBuffers, viewProjMats, cellCenter, gbufferColorRts, gbufferDepthRt, probeToRefresh,
+							 cascadeViewProjMats, shadowsRt](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+
+				const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
+				const Bool doShadows = dirLightc && dirLightc->getShadowEnabled();
+
+				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+				for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
+				{
+					const U32 rez = m_tileSize;
+					cmdb.setScissor(rez * faceIdx, 0, rez, rez);
+					cmdb.setViewport(rez * faceIdx, 0, rez, rez);
+
+					// Draw light shading
+					TraditionalDeferredLightShadingDrawInfo dsInfo;
+					dsInfo.m_viewProjectionMatrix = viewProjMats[faceIdx];
+					dsInfo.m_invViewProjectionMatrix = viewProjMats[faceIdx].getInverse();
+					dsInfo.m_cameraPosWSpace = cellCenter.xyz1();
+					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_lightbufferTexCoordsBias = Vec2(-F32(faceIdx), 0.0f);
+					dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize), 1.0f / F32(m_tileSize));
+
+					dsInfo.m_effectiveShadowDistance = (doShadows) ? probeToRefresh->getShadowsRenderRadius() : -1.0f;
+
+					if(doShadows)
+					{
+						const F32 xScale = 1.0f / 6.0f;
+						const F32 yScale = 1.0f;
+						const F32 xOffset = F32(faceIdx) * (1.0f / 6.0f);
+						const F32 yOffset = 0.0f;
+						const Mat4 atlasMtx(xScale, 0.0f, 0.0f, xOffset, 0.0f, yScale, 0.0f, yOffset, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+						const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+						dsInfo.m_dirLightMatrix = atlasMtx * biasMat4 * cascadeViewProjMats[faceIdx];
+					}
+					else
+					{
+						dsInfo.m_dirLightMatrix = Mat4::getIdentity();
+					}
+
+					dsInfo.m_visibleLightsBuffer = visibleLightsBuffers[faceIdx];
+
+					dsInfo.m_gbufferRenderTargets[0] = gbufferColorRts[0];
+					dsInfo.m_gbufferRenderTargets[1] = gbufferColorRts[1];
+					dsInfo.m_gbufferRenderTargets[2] = gbufferColorRts[2];
+					dsInfo.m_gbufferDepthRenderTarget = gbufferDepthRt;
+					dsInfo.m_directionalLightShadowmapRenderTarget = shadowsRt;
+					dsInfo.m_renderpassContext = &rgraphCtx;
+
+					m_lightShading.m_deferred.drawLights(dsInfo);
+				}
+			});
 		}
 		}
-	}
-
-	// Irradiance pass. First & 2nd bounce
-	{
-		m_giCtx->m_irradianceVolume = rgraph.importRenderTarget(m_giCtx->m_probeToUpdateThisFrame->m_volumeTexture, TextureUsageBit::kNone);
 
 
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI irradiance");
-
-		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
-			runIrradiance(rgraphCtx);
-		});
-
-		pass.newTextureDependency(giCtx->m_lightShadingRt, TextureUsageBit::kSampledCompute);
-
-		for(U32 i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
+		// Irradiance pass. First & 2nd bounce
 		{
 		{
-			pass.newTextureDependency(giCtx->m_gbufferColorRts[i], TextureUsageBit::kSampledCompute);
-		}
-
-		pass.newTextureDependency(m_giCtx->m_irradianceVolume, TextureUsageBit::kImageComputeWrite);
-	}
-}
-
-void IndirectDiffuseProbes::runGBufferInThread(RenderPassWorkContext& rgraphCtx) const
-{
-	ANKI_ASSERT(m_giCtx->m_probeToUpdateThisFrame);
-	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
-
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-	const GlobalIlluminationProbeQueueElementForRefresh& probe = *m_giCtx->m_probeToUpdateThisFrame;
-
-	const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
-
-	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];
-
-	RenderableDrawerArguments args;
-	args.m_viewMatrix = rqueue.m_viewMatrix;
-	args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
-	args.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
-	args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
-	args.m_renderingTechinuqe = RenderingTechnique::kGBuffer;
-	args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
-	args.fillMdi(m_giCtx->m_gbufferVisOut[faceIdx]);
-
-	getRenderer().getSceneDrawer().drawMdi(args, cmdb);
-
-	// It's secondary, no need to restore the state
-}
+			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI irradiance");
 
 
-void IndirectDiffuseProbes::runShadowmappingInThread(RenderPassWorkContext& rgraphCtx) const
-{
-	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
-
-	const InternalContext& giCtx = *m_giCtx;
-	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
+			pass.newTextureDependency(lightShadingRt, TextureUsageBit::kSampledCompute);
+			pass.newTextureDependency(irradianceVolume, TextureUsageBit::kImageComputeWrite);
+			for(U32 i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
+			{
+				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSampledCompute);
+			}
 
 
-	const GlobalIlluminationProbeQueueElementForRefresh& probe = *giCtx.m_probeToUpdateThisFrame;
+			pass.setWork([this, lightShadingRt, gbufferColorRts, irradianceVolume, cellIdx, probeToRefresh](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
 
 
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-	cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
+				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
 
-	const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
+				cmdb.bindShaderProgram(m_irradiance.m_grProg.get());
 
 
-	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];
+				// Bind resources
+				cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
+				rgraphCtx.bindColorTexture(0, 1, lightShadingRt);
 
 
-	const U32 rez = m_shadowMapping.m_rtDescr.m_height;
-	cmdb.setViewport(rez * faceIdx, 0, rez, rez);
-	cmdb.setScissor(rez * faceIdx, 0, rez, rez);
+				for(U32 i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
+				{
+					rgraphCtx.bindColorTexture(0, 2, gbufferColorRts[i], i);
+				}
 
 
-	RenderableDrawerArguments args;
-	args.m_viewMatrix = cascadeRenderQueue.m_viewMatrix;
-	args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
-	args.m_viewProjectionMatrix = cascadeRenderQueue.m_viewProjectionMatrix;
-	args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
-	args.m_sampler = getRenderer().getSamplers().m_trilinearRepeatAniso.get();
-	args.m_renderingTechinuqe = RenderingTechnique::kDepth;
-	args.fillMdi(giCtx.m_shadowsVisOut[faceIdx]);
+				rgraphCtx.bindImage(0, 3, irradianceVolume, TextureSubresourceInfo());
 
 
-	getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+				class
+				{
+				public:
+					IVec3 m_volumeTexel;
+					I32 m_nextTexelOffsetInU;
+				} unis;
 
 
-	// It's secondary, no need to restore the state
-}
-
-void IndirectDiffuseProbes::runLightShading(const Array<BufferOffsetRange, 6>& lightVisBuffers, RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+				U32 x, y, z;
+				unflatten3dArrayIndex(probeToRefresh->getCellCountsPerDimension().x(), probeToRefresh->getCellCountsPerDimension().y(),
+									  probeToRefresh->getCellCountsPerDimension().z(), cellIdx, x, y, z);
+				unis.m_volumeTexel = IVec3(x, y, z);
 
 
-	InternalContext& giCtx = *m_giCtx;
-	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
-	const GlobalIlluminationProbeQueueElementForRefresh& probe = *giCtx.m_probeToUpdateThisFrame;
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+				unis.m_nextTexelOffsetInU = probeToRefresh->getCellCountsPerDimension().x();
+				cmdb.setPushConstants(&unis, sizeof(unis));
 
 
-	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-	{
-		ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
-		const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
-
-		const U32 rez = m_tileSize;
-		cmdb.setScissor(rez * faceIdx, 0, rez, rez);
-		cmdb.setViewport(rez * faceIdx, 0, rez, rez);
-
-		// Draw light shading
-		TraditionalDeferredLightShadingDrawInfo dsInfo;
-		dsInfo.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
-		dsInfo.m_invViewProjectionMatrix = rqueue.m_viewProjectionMatrix.getInverse();
-		dsInfo.m_cameraPosWSpace = rqueue.m_cameraTransform.getTranslationPart().xyz1();
-		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_lightbufferTexCoordsBias = Vec2(-F32(faceIdx), 0.0f);
-		dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize), 1.0f / F32(m_tileSize));
-
-		const Bool hasDirLight = rqueue.m_directionalLight.isEnabled();
-		dsInfo.m_effectiveShadowDistance =
-			(hasDirLight && rqueue.m_directionalLight.hasShadow()) ? rqueue.m_directionalLight.m_shadowCascadesDistances[0] : -1.0f;
-		dsInfo.m_dirLightMatrix = (hasDirLight) ? rqueue.m_directionalLight.m_textureMatrices[0] : Mat4::getIdentity();
-
-		dsInfo.m_visibleLightsBuffer = lightVisBuffers[faceIdx];
-
-		dsInfo.m_gbufferRenderTargets[0] = giCtx.m_gbufferColorRts[0];
-		dsInfo.m_gbufferRenderTargets[1] = giCtx.m_gbufferColorRts[1];
-		dsInfo.m_gbufferRenderTargets[2] = giCtx.m_gbufferColorRts[2];
-		dsInfo.m_gbufferDepthRenderTarget = giCtx.m_gbufferDepthRt;
-		if(hasDirLight && rqueue.m_directionalLight.hasShadow())
-		{
-			dsInfo.m_directionalLightShadowmapRenderTarget = giCtx.m_shadowsRt;
+				// Dispatch
+				cmdb.dispatchCompute(1, 1, 1);
+			});
 		}
 		}
-		dsInfo.m_renderpassContext = &rgraphCtx;
-
-		m_lightShading.m_deferred.drawLights(dsInfo);
-	}
-}
 
 
-void IndirectDiffuseProbes::runIrradiance(RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
-
-	InternalContext& giCtx = *m_giCtx;
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
-	const GlobalIlluminationProbeQueueElementForRefresh& probe = *giCtx.m_probeToUpdateThisFrame;
-
-	cmdb.bindShaderProgram(m_irradiance.m_grProg.get());
-
-	// Bind resources
-	cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
-	rgraphCtx.bindColorTexture(0, 1, giCtx.m_lightShadingRt);
-
-	for(U32 i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
-	{
-		rgraphCtx.bindColorTexture(0, 2, giCtx.m_gbufferColorRts[i], i);
+		probeToRefresh->incrementRefreshedCells(1);
+		g_giProbeCellsRenderCountStatVar.increment(1);
 	}
 	}
-
-	rgraphCtx.bindImage(0, 3, giCtx.m_irradianceVolume, TextureSubresourceInfo());
-
-	class
-	{
-	public:
-		IVec3 m_volumeTexel;
-		I32 m_nextTexelOffsetInU;
-	} unis;
-
-	unis.m_volumeTexel = IVec3(probe.m_cellToRefresh.x(), probe.m_cellToRefresh.y(), probe.m_cellToRefresh.z());
-	unis.m_nextTexelOffsetInU = probe.m_cellCounts.x();
-	cmdb.setPushConstants(&unis, sizeof(unis));
-
-	// Dispatch
-	cmdb.dispatchCompute(1, 1, 1);
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 17 - 10
AnKi/Renderer/IndirectDiffuseProbes.h

@@ -26,13 +26,18 @@ public:
 	/// Populate the rendergraph.
 	/// Populate the rendergraph.
 	void populateRenderGraph(RenderingContext& ctx);
 	void populateRenderGraph(RenderingContext& ctx);
 
 
-	RenderTargetHandle getCurrentlyRefreshedVolumeRt() const;
+	RenderTargetHandle getCurrentlyRefreshedVolumeRt() const
+	{
+		ANKI_ASSERT(m_runCtx.m_probeVolumeHandle.isValid());
+		return m_runCtx.m_probeVolumeHandle;
+	}
 
 
-	Bool hasCurrentlyRefreshedVolumeRt() const;
+	Bool hasCurrentlyRefreshedVolumeRt() const
+	{
+		return m_runCtx.m_probeVolumeHandle.isValid();
+	}
 
 
 private:
 private:
-	class InternalContext;
-
 	class
 	class
 	{
 	{
 	public:
 	public:
@@ -63,19 +68,21 @@ private:
 		ShaderProgramPtr m_grProg;
 		ShaderProgramPtr m_grProg;
 	} m_irradiance; ///< Irradiance.
 	} m_irradiance; ///< Irradiance.
 
 
-	InternalContext* m_giCtx = nullptr;
+	static constexpr U32 kProbeCellRefreshesPerFrame = 2;
+
 	U32 m_tileSize = 0;
 	U32 m_tileSize = 0;
 
 
+	class
+	{
+	public:
+		RenderTargetHandle m_probeVolumeHandle;
+	} m_runCtx;
+
 	Error initInternal();
 	Error initInternal();
 	Error initGBuffer();
 	Error initGBuffer();
 	Error initShadowMapping();
 	Error initShadowMapping();
 	Error initLightShading();
 	Error initLightShading();
 	Error initIrradiance();
 	Error initIrradiance();
-
-	void runGBufferInThread(RenderPassWorkContext& rgraphCtx) const;
-	void runShadowmappingInThread(RenderPassWorkContext& rgraphCtx) const;
-	void runLightShading(const Array<BufferOffsetRange, 6>& lightVisBuffers, RenderPassWorkContext& rgraphCtx);
-	void runIrradiance(RenderPassWorkContext& rgraphCtx);
 };
 };
 /// @}
 /// @}
 
 

+ 0 - 6
AnKi/Renderer/ProbeReflections.cpp

@@ -406,9 +406,6 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
 		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
 		pass.newTextureDependency(m_ctx.m_gbufferDepthRt, TextureUsageBit::kAllFramebuffer, subresource);
 		pass.newTextureDependency(m_ctx.m_gbufferDepthRt, TextureUsageBit::kAllFramebuffer, subresource);
 
 
-		pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(),
-								 BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
-
 		for(U32 i = 0; i < 6; ++i)
 		for(U32 i = 0; i < 6; ++i)
 		{
 		{
 			pass.newBufferDependency(visOuts[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
 			pass.newBufferDependency(visOuts[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
@@ -460,9 +457,6 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
 		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
 		pass.newTextureDependency(m_ctx.m_shadowMapRt, TextureUsageBit::kAllFramebuffer, subresource);
 		pass.newTextureDependency(m_ctx.m_shadowMapRt, TextureUsageBit::kAllFramebuffer, subresource);
 
 
-		pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(),
-								 BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
-
 		for(U32 i = 0; i < 6; ++i)
 		for(U32 i = 0; i < 6; ++i)
 		{
 		{
 			pass.newBufferDependency(shadowVisOuts[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
 			pass.newBufferDependency(shadowVisOuts[i].m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);

+ 43 - 60
AnKi/Scene/Components/GlobalIlluminationProbeComponent.cpp

@@ -14,17 +14,7 @@ namespace anki {
 
 
 GlobalIlluminationProbeComponent::GlobalIlluminationProbeComponent(SceneNode* node)
 GlobalIlluminationProbeComponent::GlobalIlluminationProbeComponent(SceneNode* node)
 	: SceneComponent(node, kClassType)
 	: SceneComponent(node, kClassType)
-	, m_spatial(this)
 {
 {
-	for(U32 i = 0; i < 6; ++i)
-	{
-		m_frustums[i].init(FrustumType::kPerspective);
-		m_frustums[i].setPerspective(kClusterObjectFrustumNearPlane, 100.0f, kPi / 2.0f, kPi / 2.0f);
-		m_frustums[i].setWorldTransform(Transform(node->getWorldTransform().getOrigin(), Frustum::getOmnidirectionalFrustumRotations()[i], 1.0f));
-		m_frustums[i].setShadowCascadeCount(1);
-		m_frustums[i].update();
-	}
-
 	m_gpuSceneProbe.allocate();
 	m_gpuSceneProbe.allocate();
 
 
 	const Error err = ResourceManager::getSingleton().loadResource("ShaderBinaries/ClearTextureCompute.ankiprogbin", m_clearTextureProg);
 	const Error err = ResourceManager::getSingleton().loadResource("ShaderBinaries/ClearTextureCompute.ankiprogbin", m_clearTextureProg);
@@ -36,13 +26,19 @@ GlobalIlluminationProbeComponent::GlobalIlluminationProbeComponent(SceneNode* no
 
 
 GlobalIlluminationProbeComponent::~GlobalIlluminationProbeComponent()
 GlobalIlluminationProbeComponent::~GlobalIlluminationProbeComponent()
 {
 {
-	m_spatial.removeFromOctree(SceneGraph::getSingleton().getOctree());
 }
 }
 
 
 Error GlobalIlluminationProbeComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 Error GlobalIlluminationProbeComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 {
 {
-	updated = info.m_node->movedThisFrame() || m_shapeDirty;
+	const Bool moved = info.m_node->movedThisFrame();
+	updated = moved || m_shapeDirty || m_refreshDirty;
+
+	if(moved || m_shapeDirty)
+	{
+		m_cellsRefreshedCount = 0;
+	}
 
 
+	// (re-)create the volume texture
 	if(m_shapeDirty) [[unlikely]]
 	if(m_shapeDirty) [[unlikely]]
 	{
 	{
 		TextureInitInfo texInit("GiProbe");
 		TextureInitInfo texInit("GiProbe");
@@ -97,23 +93,35 @@ Error GlobalIlluminationProbeComponent::update(SceneComponentUpdateInfo& info, B
 		cmdb->flush();
 		cmdb->flush();
 	}
 	}
 
 
+	// Any update
 	if(updated) [[unlikely]]
 	if(updated) [[unlikely]]
 	{
 	{
-		m_shapeDirty = false;
-		m_cellIdxToRefresh = 0;
-
 		m_worldPos = info.m_node->getWorldTransform().getOrigin().xyz();
 		m_worldPos = info.m_node->getWorldTransform().getOrigin().xyz();
 
 
-		const Aabb aabb(-m_halfSize + m_worldPos, m_halfSize + m_worldPos);
-		m_spatial.setBoundingShape(aabb);
-
-		// New UUID
-		m_uuid = SceneGraph::getSingleton().getNewUuid();
+		// Change the UUID
+		if(m_cellsRefreshedCount == 0)
+		{
+			// Refresh starts over, get a new UUID
+			m_uuid = SceneGraph::getSingleton().getNewUuid();
+		}
+		else if(m_cellsRefreshedCount < m_totalCellCount)
+		{
+			// In the middle of the refresh process
+			ANKI_ASSERT(m_uuid != 0);
+		}
+		else
+		{
+			// Refresh it done
+			m_uuid = 0;
+		}
 
 
 		// Upload to the GPU scene
 		// Upload to the GPU scene
-		GpuSceneGlobalIlluminationProbe gpuProbe;
+		GpuSceneGlobalIlluminationProbe gpuProbe = {};
+
+		const Aabb aabb(-m_halfSize + m_worldPos, m_halfSize + m_worldPos);
 		gpuProbe.m_aabbMin = aabb.getMin().xyz();
 		gpuProbe.m_aabbMin = aabb.getMin().xyz();
 		gpuProbe.m_aabbMax = aabb.getMax().xyz();
 		gpuProbe.m_aabbMax = aabb.getMax().xyz();
+
 		gpuProbe.m_volumeTexture = m_volTexBindlessIdx;
 		gpuProbe.m_volumeTexture = m_volTexBindlessIdx;
 		gpuProbe.m_halfTexelSizeU = 1.0f / (F32(m_cellCounts.y()) * 6.0f) / 2.0f;
 		gpuProbe.m_halfTexelSizeU = 1.0f / (F32(m_cellCounts.y()) * 6.0f) / 2.0f;
 		gpuProbe.m_fadeDistance = m_fadeDistance;
 		gpuProbe.m_fadeDistance = m_fadeDistance;
@@ -122,48 +130,23 @@ Error GlobalIlluminationProbeComponent::update(SceneComponentUpdateInfo& info, B
 		m_gpuSceneProbe.uploadToGpuScene(gpuProbe);
 		m_gpuSceneProbe.uploadToGpuScene(gpuProbe);
 	}
 	}
 
 
-	if(needsRefresh()) [[unlikely]]
-	{
-		updated = true;
+	m_shapeDirty = false;
+	m_refreshDirty = false;
 
 
-		// Compute the position of the cell
-		const Aabb aabb(-m_halfSize + m_worldPos, m_halfSize + m_worldPos);
-		U32 x, y, z;
-		unflatten3dArrayIndex(m_cellCounts.x(), m_cellCounts.y(), m_cellCounts.z(), m_cellIdxToRefresh, x, y, z);
-		const Vec3 cellSize = ((m_halfSize * 2.0f) / Vec3(m_cellCounts));
-		const Vec3 halfCellSize = cellSize / 2.0f;
-		const Vec3 cellCenter = aabb.getMin().xyz() + halfCellSize + cellSize * Vec3(UVec3(x, y, z));
-
-		F32 effectiveDistance = max(m_halfSize.x(), m_halfSize.y());
-		effectiveDistance = max(effectiveDistance, m_halfSize.z());
-		effectiveDistance = max(effectiveDistance, g_probeEffectiveDistanceCVar.get());
-
-		const F32 shadowCascadeDistance = min(effectiveDistance, g_probeShadowEffectiveDistanceCVar.get());
-
-		for(U32 i = 0; i < 6; ++i)
-		{
-			m_frustums[i].setWorldTransform(Transform(cellCenter.xyz0(), Frustum::getOmnidirectionalFrustumRotations()[i], 1.0f));
-
-			m_frustums[i].setFar(effectiveDistance);
-			m_frustums[i].setShadowCascadeDistance(0, shadowCascadeDistance);
-
-			// Add something really far to force LOD 0 to be used. The importing tools create LODs with holes some times
-			// and that causes the sky to bleed to GI rendering
-			m_frustums[i].setLodDistances(
-				{effectiveDistance - 3.0f * kEpsilonf, effectiveDistance - 2.0f * kEpsilonf, effectiveDistance - 1.0f * kEpsilonf});
-		}
-	}
-
-	for(U32 i = 0; i < 6; ++i)
-	{
-		const Bool frustumUpdated = m_frustums[i].update();
-		updated = updated || frustumUpdated;
-	}
+	return Error::kNone;
+}
 
 
-	const Bool spatialUpdated = m_spatial.update(SceneGraph::getSingleton().getOctree());
-	updated = updated || spatialUpdated;
+F32 GlobalIlluminationProbeComponent::getRenderRadius() const
+{
+	F32 effectiveDistance = max(m_halfSize.x(), m_halfSize.y());
+	effectiveDistance = max(effectiveDistance, m_halfSize.z());
+	effectiveDistance = max(effectiveDistance, g_probeEffectiveDistanceCVar.get());
+	return effectiveDistance;
+}
 
 
-	return Error::kNone;
+F32 GlobalIlluminationProbeComponent::getShadowsRenderRadius() const
+{
+	return min(getRenderRadius(), g_probeShadowEffectiveDistanceCVar.get());
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 37 - 30
AnKi/Scene/Components/GlobalIlluminationProbeComponent.h

@@ -61,48 +61,58 @@ public:
 	void setFadeDistance(F32 dist)
 	void setFadeDistance(F32 dist)
 	{
 	{
 		m_fadeDistance = max(0.0f, dist);
 		m_fadeDistance = max(0.0f, dist);
+		m_shapeDirty = true;
 	}
 	}
 
 
-	WeakArray<Frustum> getFrustums()
+	/// Check if any of the probe's cells need to be re-rendered.
+	Bool getCellsNeedsRefresh() const
 	{
 	{
-		return m_frustums;
+		return m_cellsRefreshedCount < m_totalCellCount;
 	}
 	}
 
 
-	void setupGlobalIlluminationProbeQueueElement(GlobalIlluminationProbeQueueElement& el)
+	U32 getNextCellForRefresh() const
 	{
 	{
-		el.m_aabbMin = -m_halfSize + m_worldPos;
-		el.m_aabbMax = m_halfSize + m_worldPos;
-		el.m_cellCounts = m_cellCounts;
-		el.m_totalCellCount = m_totalCellCount;
-		el.m_cellSizes = (m_halfSize * 2.0f) / Vec3(m_cellCounts);
-		el.m_fadeDistance = m_fadeDistance;
-		el.m_volumeTextureBindlessIndex = m_volTexBindlessIdx;
-		el.m_index = m_gpuSceneProbe.getIndex();
+		ANKI_ASSERT(getCellsNeedsRefresh());
+		return m_cellsRefreshedCount;
 	}
 	}
 
 
-	void setupGlobalIlluminationProbeQueueElementForRefresh(GlobalIlluminationProbeQueueElementForRefresh& el)
+	/// Add to the number of texels that got refreshed this frame.
+	void incrementRefreshedCells(U32 cellCount)
 	{
 	{
-		ANKI_ASSERT(m_cellIdxToRefresh < m_totalCellCount);
-		el.m_volumeTexture = m_volTex.get();
-		unflatten3dArrayIndex(m_cellCounts.x(), m_cellCounts.y(), m_cellCounts.z(), m_cellIdxToRefresh, el.m_cellToRefresh.x(),
-							  el.m_cellToRefresh.y(), el.m_cellToRefresh.z());
-		el.m_cellCounts = m_cellCounts;
+		ANKI_ASSERT(getCellsNeedsRefresh());
+		m_cellsRefreshedCount += cellCount;
+		ANKI_ASSERT(m_cellsRefreshedCount <= m_totalCellCount);
+		m_refreshDirty = true;
 	}
 	}
 
 
-	Bool needsRefresh() const
+	U32 getUuid() const
 	{
 	{
-		return m_cellIdxToRefresh < m_totalCellCount;
+		return m_uuid;
 	}
 	}
 
 
-	void progressRefresh()
+	/// The radius around the probe's center that can infuence the rendering of the env texture.
+	F32 getRenderRadius() const;
+
+	F32 getShadowsRenderRadius() const;
+
+	const Vec3& getWorldPosition() const
 	{
 	{
-		++m_cellIdxToRefresh;
+		return m_worldPos;
 	}
 	}
 
 
-	U32 getUuid() const
+	const UVec3& getCellCountsPerDimension() const
 	{
 	{
-		ANKI_ASSERT(m_uuid);
-		return m_uuid;
+		return m_cellCounts;
+	}
+
+	U32 getCellCount() const
+	{
+		return m_totalCellCount;
+	}
+
+	Texture& getVolumeTexture() const
+	{
+		return *m_volTex;
 	}
 	}
 
 
 private:
 private:
@@ -119,17 +129,14 @@ private:
 
 
 	GpuSceneArrays::GlobalIlluminationProbe::Allocation m_gpuSceneProbe;
 	GpuSceneArrays::GlobalIlluminationProbe::Allocation m_gpuSceneProbe;
 
 
-	Array<Frustum, 6> m_frustums;
-
-	Spatial m_spatial;
-
 	ShaderProgramResourcePtr m_clearTextureProg;
 	ShaderProgramResourcePtr m_clearTextureProg;
 
 
-	U32 m_cellIdxToRefresh = 0;
-
 	U32 m_uuid = 0;
 	U32 m_uuid = 0;
 
 
+	U32 m_cellsRefreshedCount = 0;
+
 	Bool m_shapeDirty = true;
 	Bool m_shapeDirty = true;
+	Bool m_refreshDirty = true;
 
 
 	/// Recalc come values.
 	/// Recalc come values.
 	void updateMembers()
 	void updateMembers()

+ 1 - 38
AnKi/Scene/Visibility.cpp

@@ -62,15 +62,6 @@ static FrustumFlags getDirectionalLightFrustumFlags()
 	return flags;
 	return flags;
 }
 }
 
 
-static FrustumFlags getProbeFrustumFlags()
-{
-	FrustumFlags flags;
-	flags.m_gatherLightComponents = true;
-	flags.m_gatherSkyComponents = true;
-	flags.m_directionalLightsCastShadow = true;
-	return flags;
-}
-
 static FrustumFlags getCameraFrustumFlags()
 static FrustumFlags getCameraFrustumFlags()
 {
 {
 	FrustumFlags flags;
 	FrustumFlags flags;
@@ -585,35 +576,7 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 		}
 		}
 		else if(compType == GlobalIlluminationProbeComponent::kClassType)
 		else if(compType == GlobalIlluminationProbeComponent::kClassType)
 		{
 		{
-			if(!isInside())
-			{
-				continue;
-			}
-
-			GlobalIlluminationProbeComponent& giprobec = static_cast<GlobalIlluminationProbeComponent&>(comp);
-
-			if(giprobec.needsRefresh() && m_frcCtx->m_giProbesForRefreshCount.fetchAdd(1) == 0)
-			{
-				nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(framePool, 6), 6);
-				nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(framePool, 6), 6);
-
-				GlobalIlluminationProbeQueueElementForRefresh* el = newInstance<GlobalIlluminationProbeQueueElementForRefresh>(framePool);
-
-				m_frcCtx->m_giProbeForRefresh = el;
-
-				giprobec.setupGlobalIlluminationProbeQueueElementForRefresh(*el);
-				giprobec.progressRefresh();
-
-				for(U32 i = 0; i < 6; ++i)
-				{
-					el->m_renderQueues[i] = &nextQueues[i];
-					nextFrustums[i].m_frustum = &giprobec.getFrustums()[i];
-					static_cast<FrustumFlags&>(nextFrustums[i]) = getProbeFrustumFlags();
-				}
-			}
-
-			GlobalIlluminationProbeQueueElement* el = result.m_giProbes.newElement();
-			giprobec.setupGlobalIlluminationProbeQueueElement(*el);
+			ANKI_ASSERT(!"GI probes use GPU visibility from now on");
 		}
 		}
 		else if(compType == UiComponent::kClassType)
 		else if(compType == UiComponent::kClassType)
 		{
 		{