Browse Source

Break GI probes and reflection probe generation into multiple passes

Panagiotis Christopoulos Charitos 1 year ago
parent
commit
eadb7f944f

+ 1 - 1
AnKi/Gr/RenderGraph.h

@@ -250,7 +250,7 @@ public:
 		, m_type(Type::kTexture)
 	{
 		ANKI_ASSERT(handle.isValid());
-		m_texture.m_subresource.m_mipmapCount = kMaxU32; // Mark it as "whole texture"
+		m_texture.m_subresource.m_mipmapCount = kMaxU32; // Mark it as "whole texture". Some code later on will fix that up
 		m_texture.m_subresource.m_depthStencilAspect = aspect;
 	}
 

+ 162 - 199
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -68,7 +68,8 @@ Error IndirectDiffuseProbes::initGBuffer()
 	// Create RT descriptions
 	{
 		RenderTargetDescription texinit =
-			getRenderer().create2DRenderTargetDescription(m_tileSize * 6, m_tileSize, kGBufferColorRenderTargetFormats[0], "GI GBuffer");
+			getRenderer().create2DRenderTargetDescription(m_tileSize, m_tileSize, kGBufferColorRenderTargetFormats[0], "GI GBuffer");
+		texinit.m_type = TextureType::kCube;
 
 		// Create color RT descriptions
 		for(U32 i = 0; i < kGBufferColorRenderTargetCount; ++i)
@@ -80,28 +81,13 @@ Error IndirectDiffuseProbes::initGBuffer()
 		}
 
 		// Create depth RT
+		texinit.m_type = TextureType::k2D;
 		texinit.m_format = getRenderer().getDepthNoStencilFormat();
 		texinit.setName("GI GBuff Depth");
 		m_gbuffer.m_depthRtDescr = texinit;
 		m_gbuffer.m_depthRtDescr.bake();
 	}
 
-	// Create FB descr
-	{
-		m_gbuffer.m_fbDescr.m_colorAttachmentCount = kGBufferColorRenderTargetCount;
-
-		for(U j = 0; j < kGBufferColorRenderTargetCount; ++j)
-		{
-			m_gbuffer.m_fbDescr.m_colorAttachments[j].m_loadOperation = AttachmentLoadOperation::kClear;
-		}
-
-		m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
-		m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kClear;
-		m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
-
-		m_gbuffer.m_fbDescr.bake();
-	}
-
 	return Error::kNone;
 }
 
@@ -112,10 +98,10 @@ Error IndirectDiffuseProbes::initShadowMapping()
 
 	// RT descr
 	m_shadowMapping.m_rtDescr =
-		getRenderer().create2DRenderTargetDescription(resolution * 6, resolution, getRenderer().getDepthNoStencilFormat(), "GI SM");
+		getRenderer().create2DRenderTargetDescription(resolution, resolution, getRenderer().getDepthNoStencilFormat(), "GI SM");
 	m_shadowMapping.m_rtDescr.bake();
 
-	// FB descr
+	// Create the FB descr
 	m_shadowMapping.m_fbDescr.m_colorAttachmentCount = 0;
 	m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
 	m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
@@ -129,17 +115,11 @@ Error IndirectDiffuseProbes::initLightShading()
 {
 	// Init RT descr
 	{
-		m_lightShading.m_rtDescr = getRenderer().create2DRenderTargetDescription(m_tileSize * 6, m_tileSize, getRenderer().getHdrFormat(), "GI LS");
+		m_lightShading.m_rtDescr = getRenderer().create2DRenderTargetDescription(m_tileSize, m_tileSize, getRenderer().getHdrFormat(), "GI LS");
+		m_lightShading.m_rtDescr.m_type = TextureType::kCube;
 		m_lightShading.m_rtDescr.bake();
 	}
 
-	// Create FB descr
-	{
-		m_lightShading.m_fbDescr.m_colorAttachmentCount = 1;
-		m_lightShading.m_fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::kClear;
-		m_lightShading.m_fbDescr.bake();
-	}
-
 	// Init deferred
 	ANKI_CHECK(m_lightShading.m_deferred.init());
 
@@ -148,10 +128,9 @@ Error IndirectDiffuseProbes::initLightShading()
 
 Error IndirectDiffuseProbes::initIrradiance()
 {
-	ANKI_CHECK(
-		loadShaderProgram("ShaderBinaries/IrradianceDice.ankiprogbin",
-						  {{"WORKGROUP_SIZE_XY", MutatorValue(m_tileSize)}, {"LIGHT_SHADING_TEX", 0}, {"STORE_LOCATION", 0}, {"SECOND_BOUNCE", 1}},
-						  m_irradiance.m_prog, m_irradiance.m_grProg));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/IrradianceDice.ankiprogbin",
+								 {{"THREDGROUP_SIZE_SQRT", MutatorValue(m_tileSize)}, {"STORE_LOCATION", 0}, {"SECOND_BOUNCE", 1}},
+								 m_irradiance.m_prog, m_irradiance.m_grProg));
 
 	return Error::kNone;
 }
@@ -218,249 +197,233 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 	{
 		const Vec3 cellCenter = computeCellCenter(cellIdx, *probeToRefresh);
 
-		// GBuffer visibility
-		Array<GpuVisibilityOutput, 6> visOuts;
-		Array<Frustum, 6> frustums;
-		for(U32 i = 0; i < 6; ++i)
-		{
-			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 = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
-
-			FrustumGpuVisibilityInput visIn;
-			visIn.m_passesName = "GI GBuffer";
-			visIn.m_technique = RenderingTechnique::kGBuffer;
-			visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
-			visIn.m_lodReferencePoint = cellCenter;
-			visIn.m_lodDistances = lodDistances;
-			visIn.m_rgraph = &rgraph;
-			visIn.m_finalRenderTargetSize = UVec2(m_tileSize);
-
-			getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOuts[i]);
-		}
-
-		// GBuffer
-		Array<Mat4, 6> viewProjMats;
-		Array<Mat3x4, 6> viewMats;
+		// For each face do everything up to light shading
+		for(U8 f = 0; f < 6; ++f)
 		{
-			// Prepare the matrices
-			for(U32 f = 0; f < 6; ++f)
+			// GBuffer visibility
+			GpuVisibilityOutput visOut;
+			Frustum frustum;
 			{
-				viewProjMats[f] = frustums[f].getViewProjectionMatrix();
-				viewMats[f] = frustums[f].getViewMatrix();
-			}
+				frustum.setPerspective(kClusterObjectFrustumNearPlane, probeToRefresh->getRenderRadius(), kPi / 2.0f, kPi / 2.0f);
+				frustum.setWorldTransform(Transform(cellCenter.xyz0(), Frustum::getOmnidirectionalFrustumRotations()[f], 1.0f));
+				frustum.update();
 
-			// Create the pass
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI GBuffer");
-			pass.setFramebufferInfo(m_gbuffer.m_fbDescr, gbufferColorRts, gbufferDepthRt);
+				Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
-			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
-			{
-				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kFramebufferWrite);
+				FrustumGpuVisibilityInput visIn;
+				visIn.m_passesName = computeTempPassName("GI: GBuffer", cellIdx * 100 + f);
+				visIn.m_technique = RenderingTechnique::kGBuffer;
+				visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
+				visIn.m_lodReferencePoint = cellCenter;
+				visIn.m_lodDistances = lodDistances;
+				visIn.m_rgraph = &rgraph;
+				visIn.m_finalRenderTargetSize = UVec2(m_tileSize);
+
+				getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
 			}
-			pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
-			for(U32 i = 0; i < 6; ++i)
+			// GBuffer
 			{
-				pass.newBufferDependency(visOuts[i].m_someBufferHandle, BufferUsageBit::kIndirectDraw);
-			}
+				// Create the FB descriptor
+				FramebufferDescription fbDescr;
+				fbDescr.m_colorAttachmentCount = kGBufferColorRenderTargetCount;
+				for(U j = 0; j < kGBufferColorRenderTargetCount; ++j)
+				{
+					fbDescr.m_colorAttachments[j].m_loadOperation = AttachmentLoadOperation::kClear;
+					fbDescr.m_colorAttachments[j].m_surface.m_face = f;
+				}
+				fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
+				fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kClear;
+				fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
+				fbDescr.bake();
 
-			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;
+				// Create the pass
+				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("GI: GBuffer", cellIdx * 100 + f));
+				pass.setFramebufferInfo(fbDescr, gbufferColorRts, gbufferDepthRt);
 
-				const U32 viewportX = faceIdx * m_tileSize;
-				cmdb.setViewport(viewportX, 0, m_tileSize, m_tileSize);
-				cmdb.setScissor(viewportX, 0, m_tileSize, m_tileSize);
+				for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+				{
+					pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kFramebufferWrite, TextureSurfaceInfo(0, 0, f, 0));
+				}
+				pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
-				RenderableDrawerArguments args;
-				args.m_viewMatrix = viewMats[faceIdx];
-				args.m_cameraTransform = args.m_viewMatrix.getInverseTransformation();
-				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.m_viewport = UVec4(viewportX, 0, m_tileSize, m_tileSize);
-				args.fillMdi(visOuts[faceIdx]);
+				pass.newBufferDependency(visOut.m_someBufferHandle, BufferUsageBit::kIndirectDraw);
 
-				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+				pass.setWork(1, [this, visOut, viewProjMat = frustum.getViewProjectionMatrix(),
+								 viewMat = frustum.getViewMatrix()](RenderPassWorkContext& rgraphCtx) {
+					ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+					CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
-				// It's secondary, no need to restore any state
-			});
-		}
+					cmdb.setViewport(0, 0, m_tileSize, m_tileSize);
 
-		// Shadow visibility. Optional
-		Array<GpuVisibilityOutput, 6> shadowVisOuts;
-		Array<Mat4, 6> cascadeProjMats;
-		Array<Mat3x4, 6> cascadeViewMats;
-		Array<Mat4, 6> cascadeViewProjMats;
-		if(doShadows)
-		{
-			for(U32 i = 0; i < 6; ++i)
+					RenderableDrawerArguments args;
+					args.m_viewMatrix = viewMat;
+					args.m_cameraTransform = args.m_viewMatrix.getInverseTransformation();
+					args.m_viewProjectionMatrix = viewProjMat;
+					args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
+					args.m_renderingTechinuqe = RenderingTechnique::kGBuffer;
+					args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
+					args.m_viewport = UVec4(0, 0, m_tileSize, m_tileSize);
+					args.fillMdi(visOut);
+
+					getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+
+					// It's secondary, no need to restore any state
+				});
+			}
+
+			// Shadow visibility. Optional
+			GpuVisibilityOutput shadowVisOut;
+			Mat4 cascadeProjMat;
+			Mat3x4 cascadeViewMat;
+			Mat4 cascadeViewProjMat;
+			if(doShadows)
 			{
 				constexpr U32 kCascadeCount = 1;
-				dirLightc->computeCascadeFrustums(frustums[i], Array<F32, kCascadeCount>{probeToRefresh->getShadowsRenderRadius()},
-												  WeakArray<Mat4>(&cascadeProjMats[i], kCascadeCount),
-												  WeakArray<Mat3x4>(&cascadeViewMats[i], kCascadeCount));
+				dirLightc->computeCascadeFrustums(frustum, Array<F32, kCascadeCount>{probeToRefresh->getShadowsRenderRadius()},
+												  WeakArray<Mat4>(&cascadeProjMat, kCascadeCount), WeakArray<Mat3x4>(&cascadeViewMat, kCascadeCount));
 
-				cascadeViewProjMats[i] = cascadeProjMats[i] * Mat4(cascadeViewMats[i], Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+				cascadeViewProjMat = cascadeProjMat * Mat4(cascadeViewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
 
 				Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
 				FrustumGpuVisibilityInput visIn;
-				visIn.m_passesName = "GI shadows";
+				visIn.m_passesName = computeTempPassName("GI: Shadows", cellIdx * 100 + f);
 				visIn.m_technique = RenderingTechnique::kDepth;
-				visIn.m_viewProjectionMatrix = cascadeViewProjMats[i];
+				visIn.m_viewProjectionMatrix = cascadeViewProjMat;
 				visIn.m_lodReferencePoint = cellCenter;
 				visIn.m_lodDistances = lodDistances;
 				visIn.m_rgraph = &rgraph;
 				visIn.m_finalRenderTargetSize = UVec2(m_shadowMapping.m_rtDescr.m_height);
 
-				getRenderer().getGpuVisibility().populateRenderGraph(visIn, shadowVisOuts[i]);
+				getRenderer().getGpuVisibility().populateRenderGraph(visIn, shadowVisOut);
 			}
-		}
-
-		// Shadow pass. Optional
-		if(doShadows)
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI shadows");
-			pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, shadowsRt);
 
-			pass.newTextureDependency(shadowsRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
-			for(U32 i = 0; i < 6; ++i)
+			// Shadow pass. Optional
+			if(doShadows)
 			{
-				pass.newBufferDependency(shadowVisOuts[i].m_someBufferHandle, BufferUsageBit::kIndirectDraw);
-			}
+				// Create the pass
+				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("GI: Shadows", cellIdx * 100 + f));
+				pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, shadowsRt);
 
-			pass.setWork(6, [this, shadowVisOuts, cascadeViewProjMats, cascadeViewMats](RenderPassWorkContext& rgraphCtx) {
-				ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
-				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+				pass.newTextureDependency(shadowsRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+				pass.newBufferDependency(shadowVisOut.m_someBufferHandle, BufferUsageBit::kIndirectDraw);
 
-				cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
+				pass.setWork(1, [this, shadowVisOut, cascadeViewProjMat, cascadeViewMat](RenderPassWorkContext& rgraphCtx) {
+					ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+					CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
-				const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
+					cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
 
-				const U32 rez = m_shadowMapping.m_rtDescr.m_height;
-				cmdb.setViewport(rez * faceIdx, 0, rez, rez);
-				cmdb.setScissor(rez * faceIdx, 0, rez, rez);
+					const U32 rez = m_shadowMapping.m_rtDescr.m_width;
+					cmdb.setViewport(0, 0, rez, rez);
 
-				RenderableDrawerArguments args;
-				args.m_viewMatrix = cascadeViewMats[faceIdx];
-				args.m_cameraTransform = cascadeViewMats[faceIdx].getInverseTransformation();
-				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.m_viewport = UVec4(rez * faceIdx, 0, rez, rez);
-				args.fillMdi(shadowVisOuts[faceIdx]);
+					RenderableDrawerArguments args;
+					args.m_viewMatrix = cascadeViewMat;
+					args.m_cameraTransform = cascadeViewMat.getInverseTransformation();
+					args.m_viewProjectionMatrix = cascadeViewProjMat;
+					args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
+					args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
+					args.m_renderingTechinuqe = RenderingTechnique::kDepth;
+					args.m_viewport = UVec4(0, 0, rez, rez);
+					args.fillMdi(shadowVisOut);
 
-				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+					getRenderer().getSceneDrawer().drawMdi(args, cmdb);
 
-				// It's secondary, no need to restore the state
-			});
-		}
-
-		// 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 = frustums[faceIdx].getViewProjectionMatrix();
-			in.m_rgraph = &rgraph;
-			getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
-		}
-
-		// Light shading pass
-		{
-			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::kUavFragmentRead);
+					// It's secondary, no need to restore the state
+				});
 			}
 
-			pass.newTextureDependency(lightShadingRt, TextureUsageBit::kFramebufferWrite);
-
-			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+			// Light visibility
+			GpuVisibilityNonRenderablesOutput lightVis;
 			{
-				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSampledFragment);
+				GpuVisibilityNonRenderablesInput in;
+				in.m_passesName = computeTempPassName("GI: Light visibility", cellIdx * 100 + f);
+				in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
+				in.m_viewProjectionMat = frustum.getViewProjectionMatrix();
+				in.m_rgraph = &rgraph;
+				getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis);
 			}
-			pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kSampledFragment, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
-			if(shadowsRt.isValid())
+			// Light shading pass
 			{
-				pass.newTextureDependency(shadowsRt, TextureUsageBit::kSampledFragment);
-			}
+				// Create FB descr
+				FramebufferDescription fbDescr;
+				fbDescr.m_colorAttachmentCount = 1;
+				fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::kClear;
+				fbDescr.m_colorAttachments[0].m_surface.m_face = f;
+				fbDescr.bake();
 
-			pass.setWork(1, [this, visibleLightsBuffers, viewProjMats, cellCenter, gbufferColorRts, gbufferDepthRt, probeToRefresh,
-							 cascadeViewProjMats, shadowsRt](RenderPassWorkContext& rgraphCtx) {
-				ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+				// Create the pass
+				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("GI: Light shading", cellIdx * 100 + f));
+				pass.setFramebufferInfo(fbDescr, {lightShadingRt});
 
-				const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
-				const Bool doShadows = dirLightc && dirLightc->getShadowEnabled();
+				pass.newBufferDependency(lightVis.m_visiblesBufferHandle, BufferUsageBit::kUavFragmentRead);
 
-				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+				pass.newTextureDependency(lightShadingRt, TextureUsageBit::kFramebufferWrite, TextureSurfaceInfo(0, 0, f, 0));
 
-				for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
+				for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
 				{
+					pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSampledFragment, TextureSurfaceInfo(0, 0, f, 0));
+				}
+				pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kSampledFragment, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+
+				if(shadowsRt.isValid())
+				{
+					pass.newTextureDependency(shadowsRt, TextureUsageBit::kSampledFragment);
+				}
+
+				pass.setWork(1, [this, visibleLightsBuffer = lightVis.m_visiblesBuffer, viewProjMat = frustum.getViewProjectionMatrix(), cellCenter,
+								 gbufferColorRts, gbufferDepthRt, probeToRefresh, cascadeViewProjMat, shadowsRt,
+								 faceIdx = f](RenderPassWorkContext& rgraphCtx) {
+					ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
+
+					const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
+					const Bool doShadows = dirLightc && dirLightc->getShadowEnabled();
+
+					CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
 					const U32 rez = m_tileSize;
-					cmdb.setScissor(rez * faceIdx, 0, rez, rez);
-					cmdb.setViewport(rez * faceIdx, 0, rez, rez);
+					cmdb.setViewport(0, 0, rez, rez);
 
 					// Draw light shading
 					TraditionalDeferredLightShadingDrawInfo dsInfo;
-					dsInfo.m_viewProjectionMatrix = viewProjMats[faceIdx];
-					dsInfo.m_invViewProjectionMatrix = viewProjMats[faceIdx].getInverse();
+					dsInfo.m_viewProjectionMatrix = viewProjMat;
+					dsInfo.m_invViewProjectionMatrix = viewProjMat.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_viewport = UVec4(0, 0, m_tileSize, 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];
+						dsInfo.m_dirLightMatrix = biasMat4 * cascadeViewProjMat;
 					}
 					else
 					{
 						dsInfo.m_dirLightMatrix = Mat4::getIdentity();
 					}
 
-					dsInfo.m_visibleLightsBuffer = visibleLightsBuffers[faceIdx];
+					dsInfo.m_visibleLightsBuffer = visibleLightsBuffer;
 
 					dsInfo.m_gbufferRenderTargets[0] = gbufferColorRts[0];
+					dsInfo.m_gbufferRenderTargetSubresourceInfos[0].m_firstFace = faceIdx;
 					dsInfo.m_gbufferRenderTargets[1] = gbufferColorRts[1];
+					dsInfo.m_gbufferRenderTargetSubresourceInfos[1].m_firstFace = faceIdx;
 					dsInfo.m_gbufferRenderTargets[2] = gbufferColorRts[2];
+					dsInfo.m_gbufferRenderTargetSubresourceInfos[2].m_firstFace = faceIdx;
 					dsInfo.m_gbufferDepthRenderTarget = gbufferDepthRt;
 					dsInfo.m_directionalLightShadowmapRenderTarget = shadowsRt;
 					dsInfo.m_renderpassContext = &rgraphCtx;
 
 					m_lightShading.m_deferred.drawLights(dsInfo);
-				}
-			});
-		}
+				});
+			}
+		} // For all faces
 
 		// Irradiance pass. First & 2nd bounce
 		{
-			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI irradiance");
+			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(computeTempPassName("GI: Irradiance", cellIdx * 100));
 
 			pass.newTextureDependency(lightShadingRt, TextureUsageBit::kSampledCompute);
 			pass.newTextureDependency(irradianceVolume, TextureUsageBit::kUavComputeWrite);

+ 0 - 2
AnKi/Renderer/IndirectDiffuseProbes.h

@@ -42,7 +42,6 @@ private:
 	public:
 		Array<RenderTargetDescription, kGBufferColorRenderTargetCount> m_colorRtDescrs;
 		RenderTargetDescription m_depthRtDescr;
-		FramebufferDescription m_fbDescr;
 	} m_gbuffer; ///< G-buffer pass.
 
 	class
@@ -56,7 +55,6 @@ private:
 	{
 	public:
 		RenderTargetDescription m_rtDescr;
-		FramebufferDescription m_fbDescr;
 		TraditionalDeferredLightShading m_deferred;
 	} m_lightShading; ///< Light shading.
 

+ 246 - 351
AnKi/Renderer/ProbeReflections.cpp

@@ -67,13 +67,14 @@ Error ProbeReflections::initGBuffer()
 
 	// Create RT descriptions
 	{
-		RenderTargetDescription texinit = getRenderer().create2DRenderTargetDescription(m_gbuffer.m_tileSize * 6, m_gbuffer.m_tileSize,
+		RenderTargetDescription texinit = getRenderer().create2DRenderTargetDescription(m_gbuffer.m_tileSize, m_gbuffer.m_tileSize,
 																						kGBufferColorRenderTargetFormats[0], "CubeRefl GBuffer");
 
 		// Create color RT descriptions
 		for(U32 i = 0; i < kGBufferColorRenderTargetCount; ++i)
 		{
 			texinit.m_format = kGBufferColorRenderTargetFormats[i];
+			texinit.m_type = TextureType::kCube;
 			m_gbuffer.m_colorRtDescrs[i] = texinit;
 			m_gbuffer.m_colorRtDescrs[i].setName(RendererString().sprintf("CubeRefl GBuff Col #%u", i));
 			m_gbuffer.m_colorRtDescrs[i].bake();
@@ -81,27 +82,12 @@ Error ProbeReflections::initGBuffer()
 
 		// Create depth RT
 		texinit.m_format = getRenderer().getDepthNoStencilFormat();
+		texinit.m_type = TextureType::k2D;
 		texinit.setName("CubeRefl GBuff Depth");
 		m_gbuffer.m_depthRtDescr = texinit;
 		m_gbuffer.m_depthRtDescr.bake();
 	}
 
-	// Create FB descr
-	{
-		m_gbuffer.m_fbDescr.m_colorAttachmentCount = kGBufferColorRenderTargetCount;
-
-		for(U j = 0; j < kGBufferColorRenderTargetCount; ++j)
-		{
-			m_gbuffer.m_fbDescr.m_colorAttachments[j].m_loadOperation = AttachmentLoadOperation::kClear;
-		}
-
-		m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
-		m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kClear;
-		m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
-
-		m_gbuffer.m_fbDescr.bake();
-	}
-
 	return Error::kNone;
 }
 
@@ -110,17 +96,6 @@ Error ProbeReflections::initLightShading()
 	m_lightShading.m_tileSize = g_reflectionProbeResolutionCVar.get();
 	m_lightShading.m_mipCount = computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8);
 
-	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-	{
-		// Light pass FB
-		FramebufferDescription& fbDescr = m_lightShading.m_fbDescr[faceIdx];
-		ANKI_ASSERT(!fbDescr.isBacked());
-		fbDescr.m_colorAttachmentCount = 1;
-		fbDescr.m_colorAttachments[0].m_surface.m_face = faceIdx;
-		fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::kClear;
-		fbDescr.bake();
-	}
-
 	// Init deferred
 	ANKI_CHECK(m_lightShading.m_deferred.init());
 
@@ -133,12 +108,10 @@ Error ProbeReflections::initIrradiance()
 
 	// Create prog
 	{
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/IrradianceDice.ankiprogbin",
-									 {{"WORKGROUP_SIZE_XY", MutatorValue(m_irradiance.m_workgroupSize)},
-									  {"LIGHT_SHADING_TEX", 1},
-									  {"STORE_LOCATION", 1},
-									  {"SECOND_BOUNCE", 0}},
-									 m_irradiance.m_prog, m_irradiance.m_grProg));
+		ANKI_CHECK(
+			loadShaderProgram("ShaderBinaries/IrradianceDice.ankiprogbin",
+							  {{"THREDGROUP_SIZE_SQRT", MutatorValue(m_irradiance.m_workgroupSize)}, {"STORE_LOCATION", 1}, {"SECOND_BOUNCE", 0}},
+							  m_irradiance.m_prog, m_irradiance.m_grProg));
 	}
 
 	// Create buff
@@ -166,7 +139,7 @@ Error ProbeReflections::initShadowMapping()
 
 	// RT descr
 	m_shadowMapping.m_rtDescr =
-		getRenderer().create2DRenderTargetDescription(resolution * 6, resolution, getRenderer().getDepthNoStencilFormat(), "CubeRefl SM");
+		getRenderer().create2DRenderTargetDescription(resolution, resolution, getRenderer().getDepthNoStencilFormat(), "CubeRefl SM");
 	m_shadowMapping.m_rtDescr.bake();
 
 	// FB descr
@@ -179,136 +152,6 @@ Error ProbeReflections::initShadowMapping()
 	return Error::kNone;
 }
 
-void ProbeReflections::runGBuffer(const Array<GpuVisibilityOutput, 6>& visOuts, const Array<Mat4, 6>& viewProjMatx, const Array<Mat3x4, 6> viewMats,
-								  RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-
-	const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
-
-	const U32 viewportX = faceIdx * m_gbuffer.m_tileSize;
-	cmdb.setViewport(viewportX, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
-	cmdb.setScissor(viewportX, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
-
-	RenderableDrawerArguments args;
-	args.m_viewMatrix = viewMats[faceIdx];
-	args.m_cameraTransform = viewMats[faceIdx].getInverseTransformation();
-	args.m_viewProjectionMatrix = viewProjMatx[faceIdx];
-	args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care about prev mats
-	args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
-	args.m_renderingTechinuqe = RenderingTechnique::kGBuffer;
-	args.m_viewport = UVec4(viewportX, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
-	args.fillMdi(visOuts[faceIdx]);
-
-	getRenderer().getSceneDrawer().drawMdi(args, cmdb);
-}
-
-void ProbeReflections::runLightShading(U32 faceIdx, const BufferOffsetRange& visResult, const Mat4& viewProjMat, const Mat4& cascadeViewProjMat,
-									   const ReflectionProbeComponent& probe, RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_ASSERT(faceIdx <= 6);
-	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-	TraditionalDeferredLightShadingDrawInfo dsInfo;
-	dsInfo.m_viewProjectionMatrix = viewProjMat;
-	dsInfo.m_invViewProjectionMatrix = viewProjMat.getInverse();
-	dsInfo.m_cameraPosWSpace = probe.getWorldPosition().xyz1();
-	dsInfo.m_viewport = UVec4(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
-	dsInfo.m_gbufferTexCoordsScale = Vec2(1.0f / F32(m_lightShading.m_tileSize * 6), 1.0f / F32(m_lightShading.m_tileSize));
-	dsInfo.m_gbufferTexCoordsBias = Vec2(F32(faceIdx) * (1.0f / 6.0f), 0.0f);
-	dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_lightShading.m_tileSize), 1.0f / F32(m_lightShading.m_tileSize));
-	dsInfo.m_lightbufferTexCoordsBias = Vec2(0.0f, 0.0f);
-	dsInfo.m_effectiveShadowDistance = probe.getShadowsRenderRadius();
-
-	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 * cascadeViewProjMat;
-
-	dsInfo.m_visibleLightsBuffer = visResult;
-	dsInfo.m_gbufferRenderTargets[0] = m_ctx.m_gbufferColorRts[0];
-	dsInfo.m_gbufferRenderTargets[1] = m_ctx.m_gbufferColorRts[1];
-	dsInfo.m_gbufferRenderTargets[2] = m_ctx.m_gbufferColorRts[2];
-	dsInfo.m_gbufferDepthRenderTarget = m_ctx.m_gbufferDepthRt;
-	if(m_ctx.m_shadowMapRt.isValid())
-	{
-		dsInfo.m_directionalLightShadowmapRenderTarget = m_ctx.m_shadowMapRt;
-	}
-	dsInfo.m_renderpassContext = &rgraphCtx;
-
-	m_lightShading.m_deferred.drawLights(dsInfo);
-}
-
-void ProbeReflections::runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_ASSERT(faceIdx < 6);
-
-	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-	TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
-	subresource.m_mipmapCount = m_lightShading.m_mipCount;
-
-	Texture* texToBind;
-	rgraphCtx.getRenderTargetState(m_ctx.m_lightShadingRt, subresource, texToBind);
-
-	TextureViewInitInfo viewInit(texToBind, subresource);
-	TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-	rgraphCtx.m_commandBuffer->generateMipmaps2d(view.get());
-}
-
-void ProbeReflections::runIrradiance(RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-
-	cmdb.bindShaderProgram(m_irradiance.m_grProg.get());
-
-	// Bind stuff
-	cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
-
-	TextureSubresourceInfo subresource;
-	subresource.m_faceCount = 6;
-	rgraphCtx.bindTexture(0, 1, m_ctx.m_lightShadingRt, subresource);
-
-	cmdb.bindUavBuffer(0, 3, m_irradiance.m_diceValuesBuff.get(), 0, m_irradiance.m_diceValuesBuff->getSize());
-
-	// Draw
-	cmdb.dispatchCompute(1, 1, 1);
-}
-
-void ProbeReflections::runIrradianceToRefl(RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-
-	cmdb.bindShaderProgram(m_irradianceToRefl.m_grProg.get());
-
-	// Bind resources
-	cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
-
-	rgraphCtx.bindColorTexture(0, 1, m_ctx.m_gbufferColorRts[0], 0);
-	rgraphCtx.bindColorTexture(0, 1, m_ctx.m_gbufferColorRts[1], 1);
-	rgraphCtx.bindColorTexture(0, 1, m_ctx.m_gbufferColorRts[2], 2);
-
-	cmdb.bindUavBuffer(0, 2, m_irradiance.m_diceValuesBuff.get(), 0, m_irradiance.m_diceValuesBuff->getSize());
-
-	for(U8 f = 0; f < 6; ++f)
-	{
-		TextureSubresourceInfo subresource;
-		subresource.m_faceCount = 1;
-		subresource.m_firstFace = f;
-		rgraphCtx.bindUavTexture(0, 3, m_ctx.m_lightShadingRt, subresource, f);
-	}
-
-	dispatchPPCompute(cmdb, 8, 8, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
-}
-
 void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
@@ -329,274 +172,326 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 	if(probeToRefresh == nullptr || ResourceManager::getSingleton().getAsyncLoader().getTasksInFlightCount() != 0) [[likely]]
 	{
 		// Nothing to update or can't update right now, early exit
-		m_ctx.m_lightShadingRt = {};
+		m_runCtx = {};
 		return;
 	}
 
 	g_probeReflectionCountStatVar.increment(1);
 	probeToRefresh->setEnvironmentTextureAsRefreshed();
 
-#if ANKI_EXTRA_CHECKS
-	m_ctx = {};
-#endif
-
 	RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
 
-	// GBuffer visibility
-	Array<GpuVisibilityOutput, 6> visOuts;
-	Array<Frustum, 6> frustums;
-	for(U32 i = 0; i < 6; ++i)
+	// Create render targets now to save memory
+	RenderTargetHandle probeTexture = rgraph.importRenderTarget(&probeToRefresh->getReflectionTexture(), TextureUsageBit::kNone);
+	m_runCtx.m_probeTex = probeTexture;
+	BufferHandle irradianceDiceValuesBuffHandle = rgraph.importBuffer(m_irradiance.m_diceValuesBuff.get(), BufferUsageBit::kNone);
+	RenderTargetHandle gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
+	RenderTargetHandle shadowMapRt = rgraph.newRenderTarget(m_shadowMapping.m_rtDescr);
+
+	Array<RenderTargetHandle, kGBufferColorRenderTargetCount> gbufferColorRts;
+	for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
 	{
-		Frustum& frustum = frustums[i];
-		frustum.setPerspective(kClusterObjectFrustumNearPlane, probeToRefresh->getRenderRadius(), kPi / 2.0f, kPi / 2.0f);
-		frustum.setWorldTransform(Transform(probeToRefresh->getWorldPosition().xyz0(), Frustum::getOmnidirectionalFrustumRotations()[i], 1.0f));
-		frustum.update();
-
-		Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
-
-		FrustumGpuVisibilityInput visIn;
-		visIn.m_passesName = "Cube refl GBuffer";
-		visIn.m_technique = RenderingTechnique::kGBuffer;
-		visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
-		visIn.m_lodReferencePoint = probeToRefresh->getWorldPosition();
-		visIn.m_lodDistances = lodDistances;
-		visIn.m_rgraph = &rgraph;
-		visIn.m_finalRenderTargetSize = UVec2(m_gbuffer.m_tileSize);
-
-		getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOuts[i]);
+		gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
 	}
 
-	// GBuffer pass
+	for(U8 f = 0; f < 6; ++f)
 	{
-		// RTs
-		Array<RenderTargetHandle, kMaxColorRenderTargets> rts;
-		for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+		// GBuffer visibility
+		GpuVisibilityOutput visOut;
+		Frustum frustum;
 		{
-			m_ctx.m_gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
-			rts[i] = m_ctx.m_gbufferColorRts[i];
+			frustum.setPerspective(kClusterObjectFrustumNearPlane, probeToRefresh->getRenderRadius(), kPi / 2.0f, kPi / 2.0f);
+			frustum.setWorldTransform(Transform(probeToRefresh->getWorldPosition().xyz0(), Frustum::getOmnidirectionalFrustumRotations()[f], 1.0f));
+			frustum.update();
+
+			Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
+
+			FrustumGpuVisibilityInput visIn;
+			visIn.m_passesName = computeTempPassName("Cube refl: GBuffer", f);
+			visIn.m_technique = RenderingTechnique::kGBuffer;
+			visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
+			visIn.m_lodReferencePoint = probeToRefresh->getWorldPosition();
+			visIn.m_lodDistances = lodDistances;
+			visIn.m_rgraph = &rgraph;
+			visIn.m_finalRenderTargetSize = UVec2(m_gbuffer.m_tileSize);
+
+			getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
 		}
-		m_ctx.m_gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
 
-		// Prepare the matrices
-		Array<Mat4, 6> viewProjMats;
-		Array<Mat3x4, 6> viewMats;
-		for(U32 f = 0; f < 6; ++f)
+		// GBuffer pass
 		{
-			viewProjMats[f] = frustums[f].getViewProjectionMatrix();
-			viewMats[f] = frustums[f].getViewMatrix();
-		}
+			// Create the FB descr
+			FramebufferDescription fbDescr;
+			fbDescr.m_colorAttachmentCount = kGBufferColorRenderTargetCount;
+			for(U j = 0; j < kGBufferColorRenderTargetCount; ++j)
+			{
+				fbDescr.m_colorAttachments[j].m_loadOperation = AttachmentLoadOperation::kClear;
+				fbDescr.m_colorAttachments[j].m_surface.m_face = f;
+			}
+			fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
+			fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kClear;
+			fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
+			fbDescr.bake();
 
-		// Pass
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("Cube refl GBuffer");
-		pass.setFramebufferInfo(m_gbuffer.m_fbDescr, rts, m_ctx.m_gbufferDepthRt);
-		pass.setWork(6, [this, visOuts, viewProjMats, viewMats](RenderPassWorkContext& rgraphCtx) {
-			runGBuffer(visOuts, viewProjMats, viewMats, rgraphCtx);
-		});
+			// Create pass
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("Cube refl: GBuffer", f));
+			pass.setFramebufferInfo(fbDescr, gbufferColorRts, gbufferDepthRt);
 
-		for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
-		{
-			pass.newTextureDependency(m_ctx.m_gbufferColorRts[i], TextureUsageBit::kFramebufferWrite);
-		}
+			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
+			{
+				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kFramebufferWrite, TextureSurfaceInfo(0, 0, f, 0));
+			}
 
-		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
-		pass.newTextureDependency(m_ctx.m_gbufferDepthRt, TextureUsageBit::kAllFramebuffer, subresource);
+			pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+			pass.newBufferDependency(visOut.m_someBufferHandle, BufferUsageBit::kIndirectDraw);
 
-		for(U32 i = 0; i < 6; ++i)
-		{
-			pass.newBufferDependency(visOuts[i].m_someBufferHandle, BufferUsageBit::kIndirectDraw);
+			pass.setWork(1, [this, visOut, viewProjMat = frustum.getViewProjectionMatrix(),
+							 viewMat = frustum.getViewMatrix()](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
+				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+				cmdb.setViewport(0, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
+
+				RenderableDrawerArguments args;
+				args.m_viewMatrix = viewMat;
+				args.m_cameraTransform = viewMat.getInverseTransformation();
+				args.m_viewProjectionMatrix = viewProjMat;
+				args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care about prev mats
+				args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
+				args.m_renderingTechinuqe = RenderingTechnique::kGBuffer;
+				args.m_viewport = UVec4(0, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
+				args.fillMdi(visOut);
+
+				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+			});
 		}
-	}
 
-	// Shadow visibility. Optional
-	const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
-	const Bool doShadows = dirLightc && dirLightc->getShadowEnabled();
-	Array<GpuVisibilityOutput, 6> shadowVisOuts;
-	Array<Mat4, 6> cascadeViewProjMats;
-	Array<Mat3x4, 6> cascadeViewMats;
-	Array<Mat4, 6> cascadeProjMats;
-	if(doShadows)
-	{
-		for(U i = 0; i < 6; ++i)
+		// Shadow visibility. Optional
+		const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
+		const Bool doShadows = dirLightc && dirLightc->getShadowEnabled();
+		GpuVisibilityOutput shadowVisOut;
+		Mat4 cascadeViewProjMat;
+		Mat3x4 cascadeViewMat;
+		Mat4 cascadeProjMat;
+		if(doShadows)
 		{
 			constexpr U32 kCascadeCount = 1;
-			dirLightc->computeCascadeFrustums(frustums[i], Array<F32, kCascadeCount>{probeToRefresh->getShadowsRenderRadius()},
-											  WeakArray<Mat4>(&cascadeProjMats[i], kCascadeCount),
-											  WeakArray<Mat3x4>(&cascadeViewMats[i], kCascadeCount));
+			dirLightc->computeCascadeFrustums(frustum, Array<F32, kCascadeCount>{probeToRefresh->getShadowsRenderRadius()},
+											  WeakArray<Mat4>(&cascadeProjMat, kCascadeCount), WeakArray<Mat3x4>(&cascadeViewMat, kCascadeCount));
 
-			cascadeViewProjMats[i] = cascadeProjMats[i] * Mat4(cascadeViewMats[i], Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+			cascadeViewProjMat = cascadeProjMat * Mat4(cascadeViewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
 
 			Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
 			FrustumGpuVisibilityInput visIn;
-			visIn.m_passesName = "Cube refl shadows";
+			visIn.m_passesName = computeTempPassName("Cube refl: Shadows", f);
 			visIn.m_technique = RenderingTechnique::kDepth;
-			visIn.m_viewProjectionMatrix = cascadeViewProjMats[i];
+			visIn.m_viewProjectionMatrix = cascadeViewProjMat;
 			visIn.m_lodReferencePoint = probeToRefresh->getWorldPosition();
 			visIn.m_lodDistances = lodDistances;
 			visIn.m_rgraph = &rgraph;
 			visIn.m_finalRenderTargetSize = UVec2(m_shadowMapping.m_rtDescr.m_height);
 
-			getRenderer().getGpuVisibility().populateRenderGraph(visIn, shadowVisOuts[i]);
+			getRenderer().getGpuVisibility().populateRenderGraph(visIn, shadowVisOut);
 		}
-	}
 
-	// Shadows. Optional
-	if(doShadows)
-	{
-		// RT
-		m_ctx.m_shadowMapRt = rgraph.newRenderTarget(m_shadowMapping.m_rtDescr);
-
-		// Pass
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("Cube refl shadows");
-		pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, m_ctx.m_shadowMapRt);
-		pass.setWork(6, [this, shadowVisOuts, cascadeViewProjMats, cascadeViewMats](RenderPassWorkContext& rgraphCtx) {
-			runShadowMapping(shadowVisOuts, cascadeViewProjMats, cascadeViewMats, rgraphCtx);
-		});
+		// Shadows. Optional
+		if(doShadows)
+		{
+			// Pass
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("Cube refl: Shadows", f));
+			pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, shadowMapRt);
 
-		TextureSubresourceInfo subresource(DepthStencilAspectBit::kDepth);
-		pass.newTextureDependency(m_ctx.m_shadowMapRt, TextureUsageBit::kAllFramebuffer, subresource);
+			pass.newTextureDependency(shadowMapRt, TextureUsageBit::kAllFramebuffer, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+			pass.newBufferDependency(shadowVisOut.m_someBufferHandle, BufferUsageBit::kIndirectDraw);
 
-		for(U32 i = 0; i < 6; ++i)
-		{
-			pass.newBufferDependency(shadowVisOuts[i].m_someBufferHandle, BufferUsageBit::kIndirectDraw);
-		}
-	}
-	else
-	{
-		m_ctx.m_shadowMapRt = {};
-	}
+			pass.setWork(1, [this, shadowVisOut, cascadeViewProjMat, cascadeViewMat](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
 
-	// Light visibility
-	Array<GpuVisibilityNonRenderablesOutput, 6> lightVis;
-	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-	{
-		GpuVisibilityNonRenderablesInput in;
-		in.m_passesName = "Cube refl light visibility";
-		in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
-		in.m_viewProjectionMat = frustums[faceIdx].getViewProjectionMatrix();
-		in.m_rgraph = &rgraph;
-		getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
-	}
+				CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+				cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
 
-	// Light shading passes
-	{
-		// RT
-		m_ctx.m_lightShadingRt = rgraph.importRenderTarget(&probeToRefresh->getReflectionTexture(), TextureUsageBit::kNone);
+				const U32 rez = m_shadowMapping.m_rtDescr.m_height;
+				cmdb.setViewport(0, 0, rez, rez);
 
-		// Passes
-		static constexpr Array<CString, 6> passNames = {"Cube refl light shading #0", "Cube refl light shading #1", "Cube refl light shading #2",
-														"Cube refl light shading #3", "Cube refl light shading #4", "Cube refl light shading #5"};
-		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+				RenderableDrawerArguments args;
+				args.m_viewMatrix = cascadeViewMat;
+				args.m_cameraTransform = cascadeViewMat.getInverseTransformation();
+				args.m_viewProjectionMatrix = cascadeViewProjMat;
+				args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
+				args.m_sampler = getRenderer().getSamplers().m_trilinearRepeatAniso.get();
+				args.m_renderingTechinuqe = RenderingTechnique::kDepth;
+				args.m_viewport = UVec4(0, 0, rez, rez);
+				args.fillMdi(shadowVisOut);
 
-			pass.setFramebufferInfo(m_lightShading.m_fbDescr[faceIdx], {m_ctx.m_lightShadingRt});
-			pass.setWork([this, visResult = lightVis[faceIdx].m_visiblesBuffer, faceIdx, viewProjMat = frustums[faceIdx].getViewProjectionMatrix(),
-						  cascadeViewProjMat = cascadeViewProjMats[faceIdx], probeToRefresh](RenderPassWorkContext& rgraphCtx) {
-				runLightShading(faceIdx, visResult, viewProjMat, cascadeViewProjMat, *probeToRefresh, rgraphCtx);
+				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
 			});
+		}
 
-			pass.newBufferDependency(lightVis[faceIdx].m_visiblesBufferHandle, BufferUsageBit::kUavFragmentRead);
+		// Light visibility
+		GpuVisibilityNonRenderablesOutput lightVis;
+		{
+			GpuVisibilityNonRenderablesInput in;
+			in.m_passesName = computeTempPassName("Cube refl: Light visibility", f);
+			in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
+			in.m_viewProjectionMat = frustum.getViewProjectionMatrix();
+			in.m_rgraph = &rgraph;
+			getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis);
+		}
 
-			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
-			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kFramebufferWrite, subresource);
+		// Light shading pass
+		{
+			// FB descr
+			FramebufferDescription fbDescr;
+			fbDescr.m_colorAttachmentCount = 1;
+			fbDescr.m_colorAttachments[0].m_surface.m_face = f;
+			fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::kClear;
+			fbDescr.bake();
+
+			// Pass
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("Cube refl: light shading", f));
+			pass.setFramebufferInfo(fbDescr, {probeTexture});
+
+			pass.newBufferDependency(lightVis.m_visiblesBufferHandle, BufferUsageBit::kUavFragmentRead);
+			pass.newTextureDependency(probeTexture, TextureUsageBit::kFramebufferWrite, TextureSubresourceInfo(TextureSurfaceInfo(0, 0, f, 0)));
 
 			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
 			{
-				pass.newTextureDependency(m_ctx.m_gbufferColorRts[i], TextureUsageBit::kSampledFragment);
+				pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSampledFragment, TextureSurfaceInfo(0, 0, f, 0));
 			}
-			pass.newTextureDependency(m_ctx.m_gbufferDepthRt, TextureUsageBit::kSampledFragment,
-									  TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+			pass.newTextureDependency(gbufferDepthRt, TextureUsageBit::kSampledFragment, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
-			if(m_ctx.m_shadowMapRt.isValid())
+			if(shadowMapRt.isValid())
 			{
-				pass.newTextureDependency(m_ctx.m_shadowMapRt, TextureUsageBit::kSampledFragment);
+				pass.newTextureDependency(shadowMapRt, TextureUsageBit::kSampledFragment);
 			}
+
+			pass.setWork([this, visResult = lightVis.m_visiblesBuffer, viewProjMat = frustum.getViewProjectionMatrix(),
+						  cascadeViewProjMat = cascadeViewProjMat, probeToRefresh, gbufferColorRts, gbufferDepthRt, shadowMapRt,
+						  faceIdx = f](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
+
+				TraditionalDeferredLightShadingDrawInfo dsInfo;
+				dsInfo.m_viewProjectionMatrix = viewProjMat;
+				dsInfo.m_invViewProjectionMatrix = viewProjMat.getInverse();
+				dsInfo.m_cameraPosWSpace = probeToRefresh->getWorldPosition().xyz1();
+				dsInfo.m_viewport = UVec4(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
+				dsInfo.m_effectiveShadowDistance = probeToRefresh->getShadowsRenderRadius();
+
+				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 = biasMat4 * cascadeViewProjMat;
+
+				dsInfo.m_visibleLightsBuffer = visResult;
+				dsInfo.m_gbufferRenderTargets[0] = gbufferColorRts[0];
+				dsInfo.m_gbufferRenderTargetSubresourceInfos[0].m_firstFace = faceIdx;
+				dsInfo.m_gbufferRenderTargets[1] = gbufferColorRts[1];
+				dsInfo.m_gbufferRenderTargetSubresourceInfos[1].m_firstFace = faceIdx;
+				dsInfo.m_gbufferRenderTargets[2] = gbufferColorRts[2];
+				dsInfo.m_gbufferRenderTargetSubresourceInfos[2].m_firstFace = faceIdx;
+				dsInfo.m_gbufferDepthRenderTarget = gbufferDepthRt;
+				if(shadowMapRt.isValid())
+				{
+					dsInfo.m_directionalLightShadowmapRenderTarget = shadowMapRt;
+				}
+				dsInfo.m_renderpassContext = &rgraphCtx;
+
+				m_lightShading.m_deferred.drawLights(dsInfo);
+			});
 		}
-	}
+	} // For 6 faces
 
-	// Irradiance passes
+	// Compute Irradiance
 	{
-		m_ctx.m_irradianceDiceValuesBuffHandle = rgraph.importBuffer(m_irradiance.m_diceValuesBuff.get(), BufferUsageBit::kNone);
+		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("Cube refl: Irradiance");
 
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("Cube refl irradiance");
+		pass.newTextureDependency(probeTexture, TextureUsageBit::kSampledCompute);
 
-		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
-			runIrradiance(rgraphCtx);
-		});
+		pass.newBufferDependency(irradianceDiceValuesBuffHandle, BufferUsageBit::kUavComputeWrite);
 
-		// Read a cube but only one layer and level
-		TextureSubresourceInfo readSubresource;
-		readSubresource.m_faceCount = 6;
-		pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kSampledCompute, readSubresource);
+		pass.setWork([this, probeTexture](RenderPassWorkContext& rgraphCtx) {
+			ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
 
-		pass.newBufferDependency(m_ctx.m_irradianceDiceValuesBuffHandle, BufferUsageBit::kUavComputeWrite);
-	}
+			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
-	// Write irradiance back to refl
-	{
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("Cube refl apply indirect");
+			cmdb.bindShaderProgram(m_irradiance.m_grProg.get());
 
-		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
-			runIrradianceToRefl(rgraphCtx);
+			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
+
+			rgraphCtx.bindColorTexture(0, 1, probeTexture);
+
+			cmdb.bindUavBuffer(0, 3, m_irradiance.m_diceValuesBuff.get(), 0, m_irradiance.m_diceValuesBuff->getSize());
+
+			cmdb.dispatchCompute(1, 1, 1);
 		});
+	}
+
+	// Append irradiance back to refl cubemap
+	{
+		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("Cube refl: Apply indirect");
 
 		for(U i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
 		{
-			pass.newTextureDependency(m_ctx.m_gbufferColorRts[i], TextureUsageBit::kSampledCompute);
+			pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSampledCompute);
 		}
 
-		TextureSubresourceInfo subresource;
-		subresource.m_faceCount = 6;
-		pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kUavComputeRead | TextureUsageBit::kUavComputeWrite, subresource);
+		pass.newTextureDependency(probeTexture, TextureUsageBit::kUavComputeRead | TextureUsageBit::kUavComputeWrite);
+
+		pass.newBufferDependency(irradianceDiceValuesBuffHandle, BufferUsageBit::kUavComputeRead);
+
+		pass.setWork([this, gbufferColorRts, probeTexture](RenderPassWorkContext& rgraphCtx) {
+			ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
+
+			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+			cmdb.bindShaderProgram(m_irradianceToRefl.m_grProg.get());
+
+			// Bind resources
+			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
+
+			for(U i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
+			{
+				rgraphCtx.bindColorTexture(0, 1, gbufferColorRts[i], i);
+			}
+
+			cmdb.bindUavBuffer(0, 2, m_irradiance.m_diceValuesBuff.get(), 0, m_irradiance.m_diceValuesBuff->getSize());
+
+			for(U8 f = 0; f < 6; ++f)
+			{
+				TextureSubresourceInfo subresource;
+				subresource.m_faceCount = 1;
+				subresource.m_firstFace = f;
+				rgraphCtx.bindUavTexture(0, 3, probeTexture, subresource, f);
+			}
 
-		pass.newBufferDependency(m_ctx.m_irradianceDiceValuesBuffHandle, BufferUsageBit::kUavComputeRead);
+			dispatchPPCompute(cmdb, 8, 8, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
+		});
 	}
 
 	// Mipmapping "passes"
 	{
-		static constexpr Array<CString, 6> passNames = {"Cube refl gen mips #0", "Cube refl gen mips #1", "Cube refl gen mips #2",
-														"Cube refl gen mips #3", "Cube refl gen mips #4", "Cube refl gen mips #5"};
 		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
-			pass.setWork([this, faceIdx](RenderPassWorkContext& rgraphCtx) {
-				runMipmappingOfLightShading(faceIdx, rgraphCtx);
-			});
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(computeTempPassName("Cube refl: Gen mips", faceIdx));
 
 			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
 			subresource.m_mipmapCount = m_lightShading.m_mipCount;
+			pass.newTextureDependency(probeTexture, TextureUsageBit::kGenerateMipmaps, subresource);
 
-			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kGenerateMipmaps, subresource);
-		}
-	}
-}
-
-void ProbeReflections::runShadowMapping(const Array<GpuVisibilityOutput, 6>& visOuts, const Array<Mat4, 6>& viewProjMats,
-										const Array<Mat3x4, 6>& viewMats, RenderPassWorkContext& rgraphCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-	cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
+			pass.setWork([this, faceIdx, probeTexture](RenderPassWorkContext& rgraphCtx) {
+				ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
 
-	const U32 faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
+				TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
+				subresource.m_mipmapCount = m_lightShading.m_mipCount;
 
-	const U32 rez = m_shadowMapping.m_rtDescr.m_height;
-	cmdb.setViewport(rez * faceIdx, 0, rez, rez);
-	cmdb.setScissor(rez * faceIdx, 0, rez, rez);
+				Texture* texToBind;
+				rgraphCtx.getRenderTargetState(probeTexture, subresource, texToBind);
 
-	RenderableDrawerArguments args;
-	args.m_viewMatrix = viewMats[faceIdx];
-	args.m_cameraTransform = viewMats[faceIdx].getInverseTransformation();
-	args.m_viewProjectionMatrix = viewProjMats[faceIdx];
-	args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
-	args.m_sampler = getRenderer().getSamplers().m_trilinearRepeatAniso.get();
-	args.m_renderingTechinuqe = RenderingTechnique::kDepth;
-	args.m_viewport = UVec4(rez * faceIdx, 0, rez, rez);
-	args.fillMdi(visOuts[faceIdx]);
-
-	getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+				TextureViewInitInfo viewInit(texToBind, subresource);
+				TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
+				rgraphCtx.m_commandBuffer->generateMipmaps2d(view.get());
+			});
+		}
+	}
 }
 
 } // end namespace anki

+ 9 - 25
AnKi/Renderer/ProbeReflections.h

@@ -45,13 +45,13 @@ public:
 
 	RenderTargetHandle getCurrentlyRefreshedReflectionRt() const
 	{
-		ANKI_ASSERT(m_ctx.m_lightShadingRt.isValid());
-		return m_ctx.m_lightShadingRt;
+		ANKI_ASSERT(m_runCtx.m_probeTex.isValid());
+		return m_runCtx.m_probeTex;
 	}
 
 	Bool getHasCurrentlyRefreshedReflectionRt() const
 	{
-		return m_ctx.m_lightShadingRt.isValid();
+		return m_runCtx.m_probeTex.isValid();
 	}
 
 private:
@@ -61,7 +61,6 @@ private:
 		U32 m_tileSize = 0;
 		Array<RenderTargetDescription, kGBufferColorRenderTargetCount> m_colorRtDescrs;
 		RenderTargetDescription m_depthRtDescr;
-		FramebufferDescription m_fbDescr;
 	} m_gbuffer; ///< G-buffer pass.
 
 	class LS
@@ -69,7 +68,6 @@ private:
 	public:
 		U32 m_tileSize = 0;
 		U32 m_mipCount = 0;
-		Array<FramebufferDescription, 6> m_fbDescr;
 		TraditionalDeferredLightShading m_deferred;
 	} m_lightShading; ///< Light shading.
 
@@ -96,19 +94,15 @@ private:
 		FramebufferDescription m_fbDescr;
 	} m_shadowMapping;
 
-	// Other
-	ImageResourcePtr m_integrationLut;
-	SamplerPtr m_integrationLutSampler;
-
 	class
 	{
 	public:
-		Array<RenderTargetHandle, kGBufferColorRenderTargetCount> m_gbufferColorRts;
-		RenderTargetHandle m_gbufferDepthRt;
-		RenderTargetHandle m_lightShadingRt;
-		BufferHandle m_irradianceDiceValuesBuffHandle;
-		RenderTargetHandle m_shadowMapRt;
-	} m_ctx; ///< Runtime context.
+		RenderTargetHandle m_probeTex;
+	} m_runCtx;
+
+	// Other
+	ImageResourcePtr m_integrationLut;
+	SamplerPtr m_integrationLutSampler;
 
 	Error initInternal();
 	Error initGBuffer();
@@ -116,16 +110,6 @@ private:
 	Error initIrradiance();
 	Error initIrradianceToRefl();
 	Error initShadowMapping();
-
-	void runGBuffer(const Array<GpuVisibilityOutput, 6>& visOuts, const Array<Mat4, 6>& viewProjMatx, const Array<Mat3x4, 6> viewMats,
-					RenderPassWorkContext& rgraphCtx);
-	void runShadowMapping(const Array<GpuVisibilityOutput, 6>& visOuts, const Array<Mat4, 6>& viewProjMats, const Array<Mat3x4, 6>& viewMats,
-						  RenderPassWorkContext& rgraphCtx);
-	void runLightShading(U32 faceIdx, const BufferOffsetRange& visResult, const Mat4& viewProjMat, const Mat4& cascadeViewProjMat,
-						 const ReflectionProbeComponent& probe, RenderPassWorkContext& rgraphCtx);
-	void runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx);
-	void runIrradiance(RenderPassWorkContext& rgraphCtx);
-	void runIrradianceToRefl(RenderPassWorkContext& rgraphCtx);
 };
 /// @}
 

+ 7 - 0
AnKi/Renderer/RendererObject.cpp

@@ -109,4 +109,11 @@ void RendererObject::zeroBuffer(Buffer* buff)
 	fence->clientWait(16.0_sec);
 }
 
+CString RendererObject::computeTempPassName(CString name, U32 index)
+{
+	thread_local static Char buff[128];
+	snprintf(buff, sizeof(buff), "%s #%u", name.cstr(), index);
+	return buff;
+}
+
 } // end namespace anki

+ 3 - 0
AnKi/Renderer/RendererObject.h

@@ -100,6 +100,9 @@ protected:
 								   ShaderProgramPtr& grProg, CString technique = {}, ShaderTypeBit shaderTypes = ShaderTypeBit::kNone);
 
 	static void zeroBuffer(Buffer* buff);
+
+	/// Temp pass name. Output lives in global memory so use it before the next computeTempPassName call.
+	static CString computeTempPassName(CString name, U32 index);
 };
 /// @}
 

+ 7 - 13
AnKi/Renderer/Utils/TraditionalDeferredShading.cpp

@@ -71,8 +71,6 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 
 		TraditionalDeferredSkyboxConstants unis;
 		unis.m_solidColor = (isSolidColor) ? skyc->getSolidColor() : Vec3(0.0f);
-		unis.m_inputTexUvBias = info.m_gbufferTexCoordsBias;
-		unis.m_inputTexUvScale = info.m_gbufferTexCoordsScale;
 		unis.m_invertedViewProjectionMat = info.m_invViewProjectionMatrix;
 		unis.m_cameraPos = info.m_cameraPosWSpace.xyz();
 		cmdb.setPushConstants(&unis, sizeof(unis));
@@ -86,10 +84,6 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 
 		TraditionalDeferredShadingConstants* unis = allocateAndBindConstants<TraditionalDeferredShadingConstants>(cmdb, 0, 0);
 
-		unis->m_inputTexUvScale = info.m_gbufferTexCoordsScale;
-		unis->m_inputTexUvBias = info.m_gbufferTexCoordsBias;
-		unis->m_fbUvScale = info.m_lightbufferTexCoordsScale;
-		unis->m_fbUvBias = info.m_lightbufferTexCoordsBias;
 		unis->m_invViewProjMat = info.m_invViewProjectionMatrix;
 		unis->m_cameraPos = info.m_cameraPosWSpace.xyz();
 
@@ -106,7 +100,7 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 			unis->m_dirLight.m_active = 0;
 		}
 
-		cmdb.bindUavBuffer(0, 1, info.m_visibleLightsBuffer.m_buffer, info.m_visibleLightsBuffer.m_offset, info.m_visibleLightsBuffer.m_range);
+		cmdb.bindUavBuffer(0, 1, info.m_visibleLightsBuffer);
 		if(GpuSceneArrays::Light::getSingleton().getElementCount() > 0)
 		{
 			cmdb.bindUavBuffer(0, 2, GpuSceneArrays::Light::getSingleton().getBufferOffsetRange());
@@ -120,21 +114,21 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 		// NOTE: Use nearest sampler because we don't want the result to sample the near tiles
 		cmdb.bindSampler(0, 3, getRenderer().getSamplers().m_nearestNearestClamp.get());
 
-		rgraphCtx.bindColorTexture(0, 4, info.m_gbufferRenderTargets[0]);
-		rgraphCtx.bindColorTexture(0, 5, info.m_gbufferRenderTargets[1]);
-		rgraphCtx.bindColorTexture(0, 6, info.m_gbufferRenderTargets[2]);
-		rgraphCtx.bindTexture(0, 7, info.m_gbufferDepthRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+		rgraphCtx.bindTexture(0, 4, info.m_gbufferRenderTargets[0], info.m_gbufferRenderTargetSubresourceInfos[0]);
+		rgraphCtx.bindTexture(0, 5, info.m_gbufferRenderTargets[1], info.m_gbufferRenderTargetSubresourceInfos[1]);
+		rgraphCtx.bindTexture(0, 6, info.m_gbufferRenderTargets[2], info.m_gbufferRenderTargetSubresourceInfos[2]);
+		rgraphCtx.bindTexture(0, 7, info.m_gbufferDepthRenderTarget, info.m_gbufferDepthRenderTargetSubresourceInfo);
 
 		cmdb.bindSampler(0, 8, m_shadowSampler.get());
 		if(dirLightc && dirLightc->getShadowEnabled())
 		{
 			ANKI_ASSERT(info.m_directionalLightShadowmapRenderTarget.isValid());
-			rgraphCtx.bindTexture(0, 9, info.m_directionalLightShadowmapRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+			rgraphCtx.bindTexture(0, 9, info.m_directionalLightShadowmapRenderTarget, info.m_directionalLightShadowmapRenderTargetSubresourceInfo);
 		}
 		else
 		{
 			// No shadows for the dir light, bind a random depth texture (need depth because validation complains)
-			rgraphCtx.bindTexture(0, 9, info.m_gbufferDepthRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+			rgraphCtx.bindTexture(0, 9, info.m_gbufferDepthRenderTarget, info.m_gbufferDepthRenderTargetSubresourceInfo);
 		}
 
 		cmdb.bindShaderProgram(m_lightGrProg[info.m_computeSpecular].get());

+ 5 - 4
AnKi/Renderer/Utils/TraditionalDeferredShading.h

@@ -20,10 +20,6 @@ public:
 	Mat4 m_invViewProjectionMatrix;
 	Vec4 m_cameraPosWSpace;
 	UVec4 m_viewport;
-	Vec2 m_gbufferTexCoordsScale;
-	Vec2 m_gbufferTexCoordsBias;
-	Vec2 m_lightbufferTexCoordsScale;
-	Vec2 m_lightbufferTexCoordsBias;
 	F32 m_effectiveShadowDistance = -1.0f; // TODO rm
 	Mat4 m_dirLightMatrix; // TODO rm
 
@@ -33,8 +29,13 @@ public:
 
 	// Render targets
 	Array<RenderTargetHandle, kGBufferColorRenderTargetCount - 1> m_gbufferRenderTargets;
+	Array<TextureSubresourceInfo, kGBufferColorRenderTargetCount - 1> m_gbufferRenderTargetSubresourceInfos;
+
 	RenderTargetHandle m_gbufferDepthRenderTarget;
+	TextureSubresourceInfo m_gbufferDepthRenderTargetSubresourceInfo = {DepthStencilAspectBit::kDepth};
+
 	RenderTargetHandle m_directionalLightShadowmapRenderTarget;
+	TextureSubresourceInfo m_directionalLightShadowmapRenderTargetSubresourceInfo = {DepthStencilAspectBit::kDepth};
 
 	RenderPassWorkContext* m_renderpassContext = nullptr;
 };

+ 51 - 0
AnKi/Shaders/ApplyIrradianceToReflection.ankiprog

@@ -0,0 +1,51 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki technique_start comp
+#include <AnKi/Shaders/PackFunctions.hlsl>
+#include <AnKi/Shaders/LightFunctions.hlsl>
+
+[[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
+[[vk::binding(1)]] TextureCube<Vec4> g_gbufferTex[3u];
+[[vk::binding(2)]] StructuredBuffer<RVec4> g_irradianceDice;
+[[vk::binding(3)]] RWTexture2D<RVec4> g_cubeTex[6u]; // RWTexture2D because there is no RWTextureCube
+
+[numthreads(8, 8, 6)] void main(UVec3 svDispatchThreadId : SV_DISPATCHTHREADID, UVec3 svGroupThreadId : SV_GROUPTHREADID)
+{
+	const U32 faceIdx = svGroupThreadId.z;
+
+	// Compute the UVs to read the gbuffer from
+	UVec2 cubeSizeu;
+	g_cubeTex[0].GetDimensions(cubeSizeu.x, cubeSizeu.y);
+	const Vec2 cubeSize = Vec2(cubeSizeu);
+	const UVec2 dispatchThreadId = min(svDispatchThreadId.xy, cubeSizeu - 1u);
+
+	const Vec2 uv = (Vec2(dispatchThreadId) + 0.5) / Vec2(cubeSize);
+	const Vec3 sampleUv = getCubemapDirection(uvToNdc(uv), faceIdx);
+
+	// Read the gbuffer
+	GbufferInfo gbuffer = (GbufferInfo)0;
+	unpackGBufferNoVelocity(g_gbufferTex[0u].SampleLevel(g_nearestAnyClampSampler, sampleUv, 0.0),
+							g_gbufferTex[1u].SampleLevel(g_nearestAnyClampSampler, sampleUv, 0.0),
+							g_gbufferTex[2u].SampleLevel(g_nearestAnyClampSampler, sampleUv, 0.0), gbuffer);
+
+	// Sample
+	const RVec3 irradiance = sampleAmbientDice(g_irradianceDice[0u].xyz, g_irradianceDice[1u].xyz, g_irradianceDice[2u].xyz, g_irradianceDice[3u].xyz,
+											   g_irradianceDice[4u].xyz, g_irradianceDice[5u].xyz, gbuffer.m_normal);
+
+	// Compute the indirect term
+	const RVec3 indirect = gbuffer.m_diffuse * irradiance;
+
+	// Read the prev color and apply indirect
+	const RVec3 prevColor = g_cubeTex[faceIdx][dispatchThreadId].xyz;
+	const RVec3 prevColorWithIndirectDiffuse = prevColor + gbuffer.m_diffuse * indirect;
+
+	// Barrier just in case
+	GroupMemoryBarrierWithGroupSync();
+
+	// Write it back
+	g_cubeTex[faceIdx][dispatchThreadId] = RVec4(prevColorWithIndirectDiffuse, 0.0);
+}
+#pragma anki technique_end comp

+ 1 - 0
AnKi/Shaders/Functions.hlsl

@@ -225,6 +225,7 @@ Vec4 bilateralUpsample(Texture2D depthHigh, Texture2D depthLow, Texture2D colorL
 	return sum / normalize;
 }
 
+/// Compute the UV that can be passed to a cube texture. The norm is in [-1, 1].
 Vec3 getCubemapDirection(const Vec2 norm, const U32 faceIdx)
 {
 	Vec3 zDir = Vec3((faceIdx <= 1u) ? 1 : 0, (faceIdx & 2u) >> 1u, (faceIdx & 4u) >> 2u);

+ 0 - 6
AnKi/Shaders/Include/TraditionalDeferredShadingTypes.h

@@ -26,9 +26,6 @@ struct TraditionalDeferredShadingConstants
 	Vec2 m_inputTexUvScale;
 	Vec2 m_inputTexUvBias;
 
-	Vec2 m_fbUvScale;
-	Vec2 m_fbUvBias;
-
 	Mat4 m_invViewProjMat;
 
 	Vec3 m_cameraPos;
@@ -42,9 +39,6 @@ struct TraditionalDeferredSkyboxConstants
 	RVec3 m_solidColor;
 	F32 m_padding1;
 
-	Vec2 m_inputTexUvScale;
-	Vec2 m_inputTexUvBias;
-
 	Mat4 m_invertedViewProjectionMat;
 
 	Vec3 m_cameraPos;

+ 5 - 0
AnKi/Shaders/Intellisense.hlsl

@@ -150,6 +150,11 @@ using Texture3D = Texture2D<T>;
 template<typename T>
 using RWTexture3D = Texture2D<T>;
 
+template<typename T>
+struct TextureCube
+{
+};
+
 template<typename T>
 struct StructuredBuffer
 {

+ 11 - 25
AnKi/Shaders/IrradianceDice.ankiprog

@@ -5,8 +5,7 @@
 
 // Compute the irradiance given a light shading result. The irradiance will be stored in an ambient dice.
 
-#pragma anki mutator WORKGROUP_SIZE_XY 8 16 32
-#pragma anki mutator LIGHT_SHADING_TEX 0 1 // 0: texture2D, 1: textureCubeArray
+#pragma anki mutator THREDGROUP_SIZE_SQRT 8 16 32
 #pragma anki mutator STORE_LOCATION 0 1 // 0: in a 3D texture, 1: In an SSBO
 #pragma anki mutator SECOND_BOUNCE 0 1
 
@@ -18,17 +17,13 @@
 
 #define DEBUG_MODE 0 // 0: disable, 1: different color per dice face, 2: different color per cell
 
-constexpr U32 kWorkgroupSize = U32(WORKGROUP_SIZE_XY) * U32(WORKGROUP_SIZE_XY);
+constexpr U32 kThreadgroupSize = U32(THREDGROUP_SIZE_SQRT) * U32(THREDGROUP_SIZE_SQRT);
 
 [[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
-#if LIGHT_SHADING_TEX == 0
-[[vk::binding(1)]] Texture2D g_lightShadingTex2d;
-#else
 [[vk::binding(1)]] TextureCube<RVec4> g_lightShadingTexCube;
-#endif
 
 #if SECOND_BOUNCE == 1
-[[vk::binding(2)]] Texture2D g_gbufferTex[3u];
+[[vk::binding(2)]] TextureCube<Vec4> g_gbufferTex[3u];
 #endif
 
 #if STORE_LOCATION == 0
@@ -51,34 +46,27 @@ struct BufferOut
 #endif
 
 constexpr U32 kMinWaveSize = 8u;
-groupshared Vec3 s_integrationResults[6u][kWorkgroupSize / kMinWaveSize];
+groupshared Vec3 s_integrationResults[6u][kThreadgroupSize / kMinWaveSize];
 groupshared U32 s_waveIndexInsideThreadGroup;
 
 RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 {
-#if LIGHT_SHADING_TEX == 0
-	const Vec2 kInputTexSize = Vec2(U32(WORKGROUP_SIZE_XY) * 6u, U32(WORKGROUP_SIZE_XY));
-	const Vec2 uv = (Vec2(svGroupThreadId.x + U32(WORKGROUP_SIZE_XY) * face, svGroupThreadId.y) + 0.5) / kInputTexSize;
-
-	return g_lightShadingTex2d.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).rgb;
-#else
-	const Vec2 uv = (Vec2(svGroupThreadId.x, svGroupThreadId.y) + 0.5) / F32(WORKGROUP_SIZE_XY);
+	const Vec2 uv = (Vec2(svGroupThreadId.x, svGroupThreadId.y) + 0.5) / F32(THREDGROUP_SIZE_SQRT);
 	const Vec2 ndc = uvToNdc(uv);
 	const Vec3 cubeUvw = getCubemapDirection(ndc, face);
 
 	return g_lightShadingTexCube.SampleLevel(g_nearestAnyClampSampler, cubeUvw, 0.0).rgb;
-#endif
 }
 
-[numthreads(WORKGROUP_SIZE_XY, WORKGROUP_SIZE_XY, 1)] void main(UVec3 svGroupThreadId : SV_GROUPTHREADID, U32 svGroupIndex : SV_GROUPINDEX)
+[numthreads(THREDGROUP_SIZE_SQRT, THREDGROUP_SIZE_SQRT, 1)] void main(UVec3 svGroupThreadId : SV_GROUPTHREADID, U32 svGroupIndex : SV_GROUPINDEX)
 {
 	U32 wavesPerThreadGroup;
 	U32 waveIndexInsideThreadGroup;
 	ANKI_COMPUTE_WAVE_INDEX_INSIDE_THREADGROUP(svGroupIndex, s_waveIndexInsideThreadGroup, waveIndexInsideThreadGroup, wavesPerThreadGroup);
-	const F32 workgroupSizeXYf = F32(WORKGROUP_SIZE_XY);
+	const F32 threadgroupSizeSqrtf = F32(THREDGROUP_SIZE_SQRT);
 
 	// Compute the NDC used in cubeCoordSolidAngle
-	const Vec2 faceUv = (Vec2(svGroupThreadId.xy) + 0.5) / workgroupSizeXYf;
+	const Vec2 faceUv = (Vec2(svGroupThreadId.xy) + 0.5) / threadgroupSizeSqrtf;
 	const Vec2 ndc = uvToNdc(faceUv);
 
 	// Compute result for a pixel
@@ -93,7 +81,7 @@ RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 		// Compute integral part
 		const RF32 lambert = max(0.0, dot(r, diceDir));
 		const RVec3 lightShading = sampleLightShadingTexture(f, svGroupThreadId);
-		const RVec3 irradiance = lightShading * lambert * cubeCoordSolidAngle(ndc, workgroupSizeXYf);
+		const RVec3 irradiance = lightShading * lambert * cubeCoordSolidAngle(ndc, threadgroupSizeSqrtf);
 
 		// Store
 		resultFaces[f] = irradiance;
@@ -142,9 +130,7 @@ RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 		const RF32 lambert = max(0.0, dot(r, diceDir));
 
 		// Read the gbuffer
-		Vec2 gbufferUv = (Vec2(svGroupThreadId.xy) + 0.5) / workgroupSizeXYf;
-		gbufferUv.x *= 1.0 / 6.0;
-		gbufferUv.x += (1.0 / 6.0) * F32(f);
+		const Vec3 gbufferUv = getCubemapDirection(ndc, f);
 		GbufferInfo gbuffer = (GbufferInfo)0;
 		unpackGBufferNoVelocity(g_gbufferTex[0u].SampleLevel(g_nearestAnyClampSampler, gbufferUv, 0.0),
 								g_gbufferTex[1u].SampleLevel(g_nearestAnyClampSampler, gbufferUv, 0.0),
@@ -158,7 +144,7 @@ RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 
 		// Compute 2nd bounce
 		const RVec3 lightShading = sampleLightShadingTexture(f, svGroupThreadId);
-		const RVec3 irradiance = (firstBounceIrradiance + lightShading * lambert) * cubeCoordSolidAngle(ndc, workgroupSizeXYf);
+		const RVec3 irradiance = (firstBounceIrradiance + lightShading * lambert) * cubeCoordSolidAngle(ndc, threadgroupSizeSqrtf);
 
 		// Store
 		resultFaces[f] = irradiance;

+ 6 - 17
AnKi/Shaders/TraditionalDeferredShading.ankiprog

@@ -9,14 +9,7 @@
 
 // VERT
 #pragma anki technique_start vert
-#include <AnKi/Shaders/Common.hlsl>
-
-Vec4 main(U32 svVertexId : SV_VERTEXID) : SV_POSITION
-{
-	const Vec2 uv = Vec2(svVertexId & 1, svVertexId >> 1) * 2.0;
-	const Vec2 pos = uv * 2.0 - 1.0;
-	return Vec4(pos, 0.0, 1.0);
-}
+#include <AnKi/Shaders/QuadVert.hlsl>
 #pragma anki technique_end vert
 
 // FRAG
@@ -41,13 +34,9 @@ Vec4 main(U32 svVertexId : SV_VERTEXID) : SV_POSITION
 [[vk::binding(8)]] SamplerComparisonState g_shadowMapSampler;
 [[vk::binding(9)]] Texture2D<RVec4> g_shadowMap;
 
-RVec3 main(Vec4 svPosition : SV_POSITION) : SV_TARGET0
+RVec3 main(Vec2 uv : TEXCOORD) : SV_TARGET0
 {
-	// Compute UV coordinates
-	const Vec2 uvToRead = mad(Vec2(svPosition.xy), g_consts.m_inputTexUvScale, g_consts.m_inputTexUvBias);
-	const Vec2 uvToWrite = mad(Vec2(svPosition.xy), g_consts.m_fbUvScale, g_consts.m_fbUvBias);
-
-	const F32 depth = g_depthTex.SampleLevel(g_gbufferSampler, uvToRead, 0.0).r;
+	const F32 depth = g_depthTex.SampleLevel(g_gbufferSampler, uv, 0.0).r;
 	if(depth == 1.0f)
 	{
 		discard;
@@ -55,11 +44,11 @@ RVec3 main(Vec4 svPosition : SV_POSITION) : SV_TARGET0
 
 	// Decode and process gbuffer
 	GbufferInfo gbuffer = (GbufferInfo)0;
-	unpackGBufferNoVelocity(g_gbufferTex0.SampleLevel(g_gbufferSampler, uvToRead, 0.0), g_gbufferTex1.SampleLevel(g_gbufferSampler, uvToRead, 0.0),
-							g_gbufferTex2.SampleLevel(g_gbufferSampler, uvToRead, 0.0), gbuffer);
+	unpackGBufferNoVelocity(g_gbufferTex0.SampleLevel(g_gbufferSampler, uv, 0.0), g_gbufferTex1.SampleLevel(g_gbufferSampler, uv, 0.0),
+							g_gbufferTex2.SampleLevel(g_gbufferSampler, uv, 0.0), gbuffer);
 	gbuffer.m_subsurface = max(gbuffer.m_subsurface, kSubsurfaceMin * 8.0);
 
-	const Vec4 worldPos4 = mul(g_consts.m_invViewProjMat, Vec4(uvToNdc(uvToWrite), depth, 1.0));
+	const Vec4 worldPos4 = mul(g_consts.m_invViewProjMat, Vec4(uvToNdc(uv), depth, 1.0));
 	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
 
 	// Compute diff

+ 2 - 4
AnKi/Shaders/TraditionalDeferredShadingSkybox.ankiprog

@@ -24,11 +24,9 @@
 [[vk::binding(3)]] Texture2D<RVec4> g_envMapTex;
 #endif
 
-RVec3 main(Vec2 uv : TEXCOORD, Vec4 svPosition : SV_POSITION) : SV_TARGET0
+RVec3 main(Vec2 uv : TEXCOORD) : SV_TARGET0
 {
-	const Vec2 uvToRead = mad(svPosition.xy, g_consts.m_inputTexUvScale, g_consts.m_inputTexUvBias);
-
-	const F32 depth = g_depthTex.SampleLevel(g_nearestAnyClampSampler, uvToRead, 0.0).r;
+	const F32 depth = g_depthTex.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
 	if(depth != 1.0f)
 	{
 		discard;