Browse Source

Replace the 2D array used in RT shadows with a 3D texture. It's slower :(

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
a979374164

+ 1 - 1
AnKi/Renderer/LightShading.cpp

@@ -151,7 +151,7 @@ void LightShading::run(RenderPassWorkContext& rgraphCtx)
 		}
 		else
 		{
-			rgraphCtx.bindColorTexture(0, 20, m_r->getShadowmapsResolve().getRt());
+			rgraphCtx.bindColorTexture(0, 21, m_r->getShadowmapsResolve().getRt());
 		}
 
 		// Draw

+ 31 - 38
AnKi/Renderer/RtShadows.cpp

@@ -61,18 +61,18 @@ Error RtShadows::initInternal(const ConfigSet& cfg)
 
 	// RTs
 	TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(
-		m_r->getWidth(), m_r->getHeight(), Format::R8G8B8A8_UNORM,
+		m_r->getWidth(), m_r->getHeight(), Format::R8_UNORM,
 		TextureUsageBit::ALL_SAMPLED | TextureUsageBit::IMAGE_TRACE_RAYS_WRITE | TextureUsageBit::IMAGE_COMPUTE_WRITE,
 		"RtShadows");
-	texinit.m_type = TextureType::_2D_ARRAY;
-	texinit.m_layerCount = 2;
+	texinit.m_type = TextureType::_3D;
+	texinit.m_depth = MAX_RT_SHADOW_LAYERS;
 	texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
 	m_historyAndFinalRt = m_r->createAndClearRenderTarget(texinit);
 
-	m_renderRt = m_r->create2DRenderTargetDescription(m_r->getWidth() / 2, m_r->getHeight() / 2, Format::R8G8B8A8_UNORM,
+	m_renderRt = m_r->create2DRenderTargetDescription(m_r->getWidth() / 2, m_r->getHeight() / 2, Format::R8_UNORM,
 													  "RtShadowsTmp");
-	m_renderRt.m_type = TextureType::_2D_ARRAY;
-	m_renderRt.m_layerCount = 2;
+	m_renderRt.m_type = TextureType::_3D;
+	m_renderRt.m_depth = MAX_RT_SHADOW_LAYERS;
 	m_renderRt.bake();
 
 	// Misc
@@ -91,11 +91,11 @@ void RtShadows::populateRenderGraph(RenderingContext& ctx)
 	buildSbt();
 
 	// RTs
-	if(ANKI_UNLIKELY(!m_runCtx.m_historyAndFinalRtImportedOnce))
+	if(ANKI_UNLIKELY(!m_historyAndFinalRtImportedOnce))
 	{
 		m_runCtx.m_historyAndFinalRt =
 			rgraph.importRenderTarget(m_historyAndFinalRt, TextureUsageBit::SAMPLED_FRAGMENT);
-		m_runCtx.m_historyAndFinalRtImportedOnce = true;
+		m_historyAndFinalRtImportedOnce = true;
 	}
 	else
 	{
@@ -143,6 +143,7 @@ void RtShadows::populateRenderGraph(RenderingContext& ctx)
 	{
 		RenderQueue& rqueue = *m_runCtx.m_ctx->m_renderQueue;
 		m_runCtx.m_layersWithRejectedHistory.unsetAll();
+		m_runCtx.m_activeShadowLayerMask = 0;
 
 		if(rqueue.m_directionalLight.hasShadow())
 		{
@@ -153,8 +154,9 @@ void RtShadows::populateRenderGraph(RenderingContext& ctx)
 			ANKI_ASSERT(layerFound && "Directional can't fail");
 
 			rqueue.m_directionalLight.m_shadowLayer = U8(layerIdx);
-			ANKI_ASSERT(rqueue.m_directionalLight.m_shadowLayer < MAX_SHADOW_LAYERS);
+			ANKI_ASSERT(rqueue.m_directionalLight.m_shadowLayer < MAX_RT_SHADOW_LAYERS);
 			m_runCtx.m_layersWithRejectedHistory.set(layerIdx, rejectHistory);
+			m_runCtx.m_activeShadowLayerMask |= 1 << layerIdx;
 		}
 
 		for(PointLightQueueElement& light : rqueue.m_pointLights)
@@ -171,8 +173,9 @@ void RtShadows::populateRenderGraph(RenderingContext& ctx)
 			if(layerFound)
 			{
 				light.m_shadowLayer = U8(layerIdx);
-				ANKI_ASSERT(light.m_shadowLayer < MAX_SHADOW_LAYERS);
+				ANKI_ASSERT(light.m_shadowLayer < MAX_RT_SHADOW_LAYERS);
 				m_runCtx.m_layersWithRejectedHistory.set(layerIdx, rejectHistory);
+				m_runCtx.m_activeShadowLayerMask |= 1 << layerIdx;
 			}
 			else
 			{
@@ -195,8 +198,9 @@ void RtShadows::populateRenderGraph(RenderingContext& ctx)
 			if(layerFound)
 			{
 				light.m_shadowLayer = U8(layerIdx);
-				ANKI_ASSERT(light.m_shadowLayer < MAX_SHADOW_LAYERS);
+				ANKI_ASSERT(light.m_shadowLayer < MAX_RT_SHADOW_LAYERS);
 				m_runCtx.m_layersWithRejectedHistory.set(layerIdx, rejectHistory);
+				m_runCtx.m_activeShadowLayerMask |= 1 << layerIdx;
 			}
 			else
 			{
@@ -217,10 +221,7 @@ void RtShadows::run(RenderPassWorkContext& rgraphCtx)
 
 	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearRepeat);
 
-	TextureSubresourceInfo subresource;
-	rgraphCtx.bindImage(0, 1, m_runCtx.m_renderRt, subresource, 0);
-	subresource.m_firstLayer = 1;
-	rgraphCtx.bindImage(0, 1, m_runCtx.m_renderRt, subresource, 1);
+	rgraphCtx.bindImage(0, 1, m_runCtx.m_renderRt, TextureSubresourceInfo());
 
 	rgraphCtx.bindColorTexture(0, 2, m_runCtx.m_historyAndFinalRt);
 	cmdb->bindSampler(0, 3, m_r->getSamplers().m_trilinearClamp);
@@ -241,12 +242,13 @@ void RtShadows::run(RenderPassWorkContext& rgraphCtx)
 
 	cmdb->bindAllBindless(1);
 
-	Array<F32, MAX_SHADOW_LAYERS> rejectFactors;
-	for(U32 i = 0; i < MAX_SHADOW_LAYERS; ++i)
+	RtShadowsUniforms unis;
+	unis.activeShadowLayerMask = m_runCtx.m_activeShadowLayerMask;
+	for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
 	{
-		rejectFactors[i] = F32(m_runCtx.m_layersWithRejectedHistory.get(i));
+		unis.historyRejectFactor[i] = F32(m_runCtx.m_layersWithRejectedHistory.get(i));
 	}
-	cmdb->setPushConstants(&rejectFactors, sizeof(rejectFactors));
+	cmdb->setPushConstants(&unis, sizeof(unis));
 
 	cmdb->traceRays(m_runCtx.m_sbtBuffer, m_runCtx.m_sbtOffset, m_sbtRecordSize, m_runCtx.m_hitGroupCount, 1,
 					m_r->getWidth() / 2, m_r->getHeight() / 2, 1);
@@ -263,22 +265,13 @@ void RtShadows::runDenoise(RenderPassWorkContext& rgraphCtx)
 	rgraphCtx.bindTexture(0, 2, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
 	rgraphCtx.bindColorTexture(0, 3, m_r->getGBuffer().getColorRt(2));
 
-	TextureSubresourceInfo subresource;
-	rgraphCtx.bindImage(0, 4, m_runCtx.m_historyAndFinalRt, subresource, 0);
-	subresource.m_firstLayer = 1;
-	rgraphCtx.bindImage(0, 4, m_runCtx.m_historyAndFinalRt, subresource, 1);
+	rgraphCtx.bindImage(0, 4, m_runCtx.m_historyAndFinalRt, TextureSubresourceInfo());
 
-	class PC
-	{
-	public:
-		Mat4 m_invViewProjMat;
-		Vec3 m_padding;
-		F32 m_time;
-	} pc;
-
-	pc.m_invViewProjMat = m_runCtx.m_ctx->m_matrices.m_viewProjectionJitter.getInverse();
-	pc.m_time = F32(m_r->getGlobalTimestamp());
-	cmdb->setPushConstants(&pc, sizeof(pc));
+	RtShadowsDenoiseUniforms unis;
+	unis.invViewProjMat = m_runCtx.m_ctx->m_matrices.m_viewProjectionJitter.getInverse();
+	unis.time = F32(m_r->getGlobalTimestamp());
+	unis.activeShadowLayerMask = m_runCtx.m_activeShadowLayerMask;
+	cmdb->setPushConstants(&unis, sizeof(unis));
 
 	dispatchPPCompute(cmdb, 8, 8, m_r->getWidth(), m_r->getHeight());
 }
@@ -339,9 +332,9 @@ Bool RtShadows::findShadowLayer(U64 lightUuid, U32& layerIdx, Bool& rejectHistor
 	U64 nextBestLayerFame = crntFrame;
 	rejectHistoryBuffer = false;
 
-	for(U32 i = 0; i < m_runCtx.m_shadowLayers.getSize(); ++i)
+	for(U32 i = 0; i < m_shadowLayers.getSize(); ++i)
 	{
-		ShadowLayer& layer = m_runCtx.m_shadowLayers[i];
+		ShadowLayer& layer = m_shadowLayers[i];
 		if(layer.m_lightUuid == lightUuid && layer.m_frameLastUsed == crntFrame - 1)
 		{
 			// Found it being used last frame
@@ -370,8 +363,8 @@ Bool RtShadows::findShadowLayer(U64 lightUuid, U32& layerIdx, Bool& rejectHistor
 	if(layerIdx == MAX_U32 && nextBestLayerIdx != MAX_U32)
 	{
 		layerIdx = nextBestLayerIdx;
-		m_runCtx.m_shadowLayers[nextBestLayerIdx].m_frameLastUsed = crntFrame;
-		m_runCtx.m_shadowLayers[nextBestLayerIdx].m_lightUuid = lightUuid;
+		m_shadowLayers[nextBestLayerIdx].m_frameLastUsed = crntFrame;
+		m_shadowLayers[nextBestLayerIdx].m_lightUuid = lightUuid;
 		rejectHistoryBuffer = true;
 	}
 

+ 12 - 10
AnKi/Renderer/RtShadows.h

@@ -9,6 +9,7 @@
 #include <AnKi/Renderer/RendererObject.h>
 #include <AnKi/Resource/TextureResource.h>
 #include <AnKi/Util/BitSet.h>
+#include <AnKi/Shaders/Include/RtShadows.h>
 
 namespace anki
 {
@@ -44,6 +45,13 @@ public:
 	}
 
 public:
+	class ShadowLayer
+	{
+	public:
+		U64 m_lightUuid = MAX_U64;
+		U64 m_frameLastUsed = MAX_U64;
+	};
+
 	ShaderProgramPtr m_grProg;
 	TexturePtr m_historyAndFinalRt;
 	RenderTargetDescription m_renderRt;
@@ -53,14 +61,9 @@ public:
 
 	U32 m_sbtRecordSize = 256;
 
-	static constexpr U32 MAX_SHADOW_LAYERS = 8;
+	Array<ShadowLayer, MAX_RT_SHADOW_LAYERS> m_shadowLayers;
 
-	class ShadowLayer
-	{
-	public:
-		U64 m_lightUuid = MAX_U64;
-		U64 m_frameLastUsed = MAX_U64;
-	};
+	Bool m_historyAndFinalRtImportedOnce = false;
 
 	class
 	{
@@ -69,14 +72,13 @@ public:
 
 		RenderTargetHandle m_renderRt;
 		RenderTargetHandle m_historyAndFinalRt;
-		Bool m_historyAndFinalRtImportedOnce = false;
 
 		BufferPtr m_sbtBuffer;
 		PtrSize m_sbtOffset;
 		U32 m_hitGroupCount = 0;
 
-		Array<ShadowLayer, MAX_SHADOW_LAYERS> m_shadowLayers;
-		BitSet<MAX_SHADOW_LAYERS, U8> m_layersWithRejectedHistory = {false};
+		BitSet<MAX_RT_SHADOW_LAYERS, U8> m_layersWithRejectedHistory = {false};
+		U32 m_activeShadowLayerMask = 0;
 	} m_runCtx;
 
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);

+ 29 - 0
AnKi/Shaders/Include/RtShadows.h

@@ -0,0 +1,29 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Shaders/Include/Common.h>
+
+ANKI_BEGIN_NAMESPACE
+
+const U32 MAX_RT_SHADOW_LAYERS = 8u;
+
+struct RtShadowsUniforms
+{
+	F32 historyRejectFactor[MAX_RT_SHADOW_LAYERS]; // 1.0 means reject, 0.0 not reject
+	U32 activeShadowLayerMask;
+	U32 padding[3];
+};
+
+struct RtShadowsDenoiseUniforms
+{
+	Mat4 invViewProjMat;
+	F32 time;
+	U32 activeShadowLayerMask;
+	U32 padding[2];
+};
+
+ANKI_END_NAMESPACE

+ 14 - 18
AnKi/Shaders/LightShading.ankiprog

@@ -35,6 +35,7 @@ void main()
 #pragma anki start frag
 #include <AnKi/Shaders/Pack.glsl>
 #include <AnKi/Shaders/Functions.glsl>
+#include <AnKi/Shaders/Include/RtShadows.h>
 
 #define LIGHT_SET 0
 #define LIGHT_COMMON_UNIS_BINDING 0
@@ -54,7 +55,11 @@ layout(set = 0, binding = 16) uniform texture2D u_msDepthRt;
 layout(set = 0, binding = 17) uniform texture2D u_ssrRt;
 layout(set = 0, binding = 18) uniform texture2D u_ssaoRt;
 layout(set = 0, binding = 19) uniform texture2D u_ssgiRt;
-layout(set = 0, binding = 20) uniform texture2DArray u_resolvedSm;
+#if USE_SHADOW_LAYERS
+layout(set = 0, binding = 20) uniform texture3D u_shadowLayersTex;
+#else
+layout(set = 0, binding = 21) uniform texture2D u_resolvedSm;
+#endif
 
 layout(location = 0) in Vec2 in_uv;
 layout(location = 1) in Vec2 in_clusterIJ;
@@ -103,20 +108,8 @@ void main()
 	gbuffer.m_subsurface = max(gbuffer.m_subsurface, SUBSURFACE_MIN);
 
 	// SM
-#if USE_SHADOW_LAYERS
-	const Vec4 resolvedSm0 = textureLod(u_resolvedSm, u_trilinearClampSampler, Vec3(in_uv, 0.0), 0.0);
-	const Vec4 resolvedSm1 = textureLod(u_resolvedSm, u_trilinearClampSampler, Vec3(in_uv, 1.0), 0.0);
-	F32 resolvedSm[8];
-	resolvedSm[0] = resolvedSm0[0];
-	resolvedSm[1] = resolvedSm0[1];
-	resolvedSm[2] = resolvedSm0[2];
-	resolvedSm[3] = resolvedSm0[3];
-	resolvedSm[4] = resolvedSm1[0];
-	resolvedSm[5] = resolvedSm1[1];
-	resolvedSm[6] = resolvedSm1[2];
-	resolvedSm[7] = resolvedSm1[3];
-#else
-	Vec4 resolvedSm = textureLod(u_resolvedSm, u_trilinearClampSampler, Vec3(in_uv, 0.0), 0.0);
+#if !USE_SHADOW_LAYERS
+	Vec4 resolvedSm = textureLod(u_resolvedSm, u_trilinearClampSampler, in_uv, 0.0);
 	U32 resolvedSmIdx = 0;
 #endif
 
@@ -135,7 +128,8 @@ void main()
 		if(u_dirLight.m_cascadeCount > 0)
 		{
 #if USE_SHADOW_LAYERS
-			shadowFactor = resolvedSm[u_dirLight.m_shadowLayer];
+			const F32 w = (F32(u_dirLight.m_shadowLayer) + 0.5) / F32(MAX_RT_SHADOW_LAYERS);
+			shadowFactor = textureLod(u_shadowLayersTex, u_trilinearClampSampler, Vec3(in_uv, w), 0.0).r;
 #else
 			shadowFactor = resolvedSm[0];
 			++resolvedSmIdx;
@@ -167,7 +161,8 @@ void main()
 		ANKI_BRANCH if(light.m_shadowAtlasTileScale >= 0.0)
 		{
 #if USE_SHADOW_LAYERS
-			const F32 shadow = resolvedSm[light.m_shadowLayer];
+			const F32 w = (F32(light.m_shadowLayer) + 0.5) / F32(MAX_RT_SHADOW_LAYERS);
+			const F32 shadow = textureLod(u_shadowLayersTex, u_trilinearClampSampler, Vec3(in_uv, w), 0.0).r;
 #else
 			const F32 shadow = resolvedSm[resolvedSmIdx++];
 #endif
@@ -190,7 +185,8 @@ void main()
 		ANKI_BRANCH if(shadowmapLayerIdx >= 0.0)
 		{
 #if USE_SHADOW_LAYERS
-			const F32 shadow = resolvedSm[light.m_shadowLayer];
+			const F32 w = (F32(light.m_shadowLayer) + 0.5) / F32(MAX_RT_SHADOW_LAYERS);
+			const F32 shadow = textureLod(u_shadowLayersTex, u_trilinearClampSampler, Vec3(in_uv, w), 0.0).r;
 #else
 			const F32 shadow = resolvedSm[resolvedSmIdx++];
 #endif

+ 31 - 19
AnKi/Shaders/RtShadowsDenoise.ankiprog

@@ -12,26 +12,25 @@ ANKI_SPECIALIZATION_CONSTANT_U32(SPIRAL_TURN_COUNT, 4, 1);
 
 #include <AnKi/Shaders/BilateralFilter.glsl>
 #include <AnKi/Shaders/Pack.glsl>
+#include <AnKi/Shaders/Include/RtShadows.h>
 
 const UVec2 WORKGROUP_SIZE = UVec2(8u, 8u);
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
 
 layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
-layout(set = 0, binding = 1) uniform texture2DArray u_inTex;
+layout(set = 0, binding = 1) uniform texture3D u_inTex;
 layout(set = 0, binding = 2) uniform texture2D u_depthTex;
 layout(set = 0, binding = 3) uniform texture2D u_gbuffer2Tex;
-layout(set = 0, binding = 4) writeonly uniform image2D u_outImg[2];
+layout(set = 0, binding = 4) writeonly uniform image3D u_outImg;
 
-layout(std140, push_constant, row_major) uniform b_pc
+layout(std430, push_constant, row_major) uniform b_pc
 {
-	Mat4 u_invViewProjMat;
-	Vec3 m_padding;
-	F32 u_time;
+	RtShadowsDenoiseUniforms u_unis;
 };
 
 Vec3 unproject(Vec2 ndc, F32 depth)
 {
-	const Vec4 worldPos4 = u_invViewProjMat * Vec4(ndc, depth, 1.0);
+	const Vec4 worldPos4 = u_unis.invViewProjMat * Vec4(ndc, depth, 1.0);
 	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
 	return worldPos;
 }
@@ -48,8 +47,16 @@ void main()
 	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(OUT_IMAGE_SIZE);
 
 	// Reference
-	Vec4 color0 = textureLod(u_inTex, u_linearAnyClampSampler, Vec3(uv, 0.0), 0.0);
-	Vec4 color1 = textureLod(u_inTex, u_linearAnyClampSampler, Vec3(uv, 1.0), 0.0);
+	F32 shadowFactors[MAX_RT_SHADOW_LAYERS];
+	ANKI_UNROLL for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
+	{
+		if((u_unis.activeShadowLayerMask & (1 << i)) != 0)
+		{
+			const F32 w = (F32(i) + 0.5) / F32(MAX_RT_SHADOW_LAYERS);
+			shadowFactors[i] = textureLod(u_inTex, u_linearAnyClampSampler, Vec3(uv, w), 0.0).r;
+		}
+	}
+
 	F32 weight = 1.0;
 
 	BilateralSample ref;
@@ -59,7 +66,7 @@ void main()
 
 	// Sample
 	SpatialBilateralContext ctx =
-		spatialBilateralInit(SAMPLE_COUNT, gl_GlobalInvocationID.xy, PIXEL_RADIUS, SPIRAL_TURN_COUNT, u_time);
+		spatialBilateralInit(SAMPLE_COUNT, gl_GlobalInvocationID.xy, PIXEL_RADIUS, SPIRAL_TURN_COUNT, u_unis.time);
 
 	for(U32 i = 0; i < SAMPLE_COUNT; ++i)
 	{
@@ -80,18 +87,23 @@ void main()
 		const F32 w = calculateBilateralWeight(crnt, ref, config);
 		weight += w;
 
-		const Vec4 sampleColor0 = texelFetch(u_inTex, IVec3(unormalizedUvs / 2, 0), 0);
-		const Vec4 sampleColor1 = texelFetch(u_inTex, IVec3(unormalizedUvs / 2, 1), 0);
-		color0 += sampleColor0 * w;
-		color1 += sampleColor1 * w;
+		ANKI_UNROLL for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
+		{
+			if((u_unis.activeShadowLayerMask & (1 << i)) != 0)
+			{
+				shadowFactors[i] += texelFetch(u_inTex, IVec3(unormalizedUvs / 2, i), 0).r * w;
+			}
+		}
 	}
 
-	color0 /= weight;
-	color1 /= weight;
-
 	// Write value
-	imageStore(u_outImg[0], IVec2(gl_GlobalInvocationID.xy), color0);
-	imageStore(u_outImg[1], IVec2(gl_GlobalInvocationID.xy), color1);
+	ANKI_UNROLL for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
+	{
+		if((u_unis.activeShadowLayerMask & (1 << i)) != 0)
+		{
+			imageStore(u_outImg, IVec3(gl_GlobalInvocationID.xy, i), Vec4(shadowFactors[i] / weight));
+		}
+	}
 }
 
 #pragma anki end

+ 62 - 28
AnKi/Shaders/RtShadowsRayGen.ankiprog

@@ -8,9 +8,13 @@
 
 #pragma anki start rgen
 
+#include <AnKi/Shaders/ImportanceSampling.glsl>
+#include <AnKi/Shaders/Pack.glsl>
+#include <AnKi/Shaders/Include/RtShadows.h>
+
 layout(set = 0, binding = 0) uniform sampler u_trilinearRepeatSampler; // Used by the hit shaders
-layout(set = 0, binding = 1) uniform image2D u_outImg[2];
-layout(set = 0, binding = 2) uniform texture2DArray u_historyRt;
+layout(set = 0, binding = 1) uniform image3D u_outImg;
+layout(set = 0, binding = 2) uniform texture3D u_historyRt;
 layout(set = 0, binding = 3) uniform sampler u_linearAnyClampSampler;
 layout(set = 0, binding = 4) uniform texture2D u_depthRt;
 layout(set = 0, binding = 5) uniform texture2D u_motionVectorsRt;
@@ -23,22 +27,16 @@ layout(set = 0, binding = 8) uniform accelerationStructureEXT u_tlas;
 #define LIGHT_LIGHTS_BINDING 10
 #define LIGHT_CLUSTERS_BINDING 13
 #include <AnKi/Shaders/ClusteredShadingCommon.glsl>
-#include <AnKi/Shaders/ImportanceSampling.glsl>
-#include <AnKi/Shaders/Pack.glsl>
 
 ANKI_BINDLESS_SET(1); // Used by the hit shaders
 
-layout(push_constant) uniform b_pc
+layout(push_constant, std430) uniform b_pc
 {
-	Vec4 u_historyRejectFactor0; // 1.0 means reject, 0.0 not reject
-	Vec4 u_historyRejectFactor1;
+	RtShadowsUniforms u_unis;
 };
 
 layout(location = 0) rayPayloadEXT F32 g_payload;
 
-#define readDepth(texture_, uv, offsetX, offsetY) \
-	textureLodOffset(sampler2D(texture_, u_linearAnyClampSampler), uv, 0.0, IVec2(offsetX, offsetY)).r
-
 F32 trace(const Vec3 rayOrigin, const Vec3 rayDir, F32 tMax)
 {
 	const U32 flags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT;
@@ -66,8 +64,13 @@ void main()
 
 	if(depth == 1.0)
 	{
-		imageStore(u_outImg[0], IVec2(gl_LaunchIDEXT.xy), Vec4(0.0));
-		imageStore(u_outImg[1], IVec2(gl_LaunchIDEXT.xy), Vec4(0.0));
+		ANKI_UNROLL for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
+		{
+			if((u_unis.activeShadowLayerMask & (1 << i)) != 0)
+			{
+				imageStore(u_outImg, IVec3(gl_LaunchIDEXT.xy, i), Vec4(0.0));
+			}
+		}
 		return;
 	}
 
@@ -79,10 +82,10 @@ void main()
 											   u_lightingUniforms.m_clusterCount.y);
 	U32 idxOffset = u_clusters[clusterIdx];
 
-	F32 shadowFactors[8];
-	ANKI_UNROLL for(U32 i = 0; i < 8; ++i)
+	F32 shadowFactors[MAX_RT_SHADOW_LAYERS];
+	ANKI_UNROLL for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
 	{
-		shadowFactors[i] = 0.0;
+		shadowFactors[i] = -1.0; // -1.0 means that this layer's pixel is outside the influence of light
 	}
 
 	// Get a random factor
@@ -96,10 +99,17 @@ void main()
 		const Vec3 rayDir = normalize(dirLightPos - worldPos);
 
 		const F32 lambertTerm = dot(rayDir, normal);
+		F32 shadowFactor;
 		ANKI_BRANCH if(lambertTerm > 0.0)
 		{
-			shadowFactors[u_dirLight.m_shadowLayer] = trace(worldPos, rayDir, 10000.0);
+			shadowFactor = trace(worldPos, rayDir, 10000.0);
 		}
+		else
+		{
+			shadowFactor = 0.0;
+		}
+
+		shadowFactors[u_dirLight.m_shadowLayer] = shadowFactor;
 	}
 
 	// Point lights
@@ -116,10 +126,17 @@ void main()
 			const Vec3 rayDir = toLight / distanceToLight; // normalize
 
 			const F32 lambertTerm = dot(rayDir, normal);
+			F32 shadowFactor;
 			ANKI_BRANCH if(lambertTerm > 0.0)
 			{
-				shadowFactors[light.m_shadowLayer] = trace(worldPos, rayDir, distanceToLight);
+				shadowFactor = trace(worldPos, rayDir, distanceToLight);
+			}
+			else
+			{
+				shadowFactor = 0.0;
 			}
+
+			shadowFactors[light.m_shadowLayer] = shadowFactor;
 		}
 	}
 
@@ -136,16 +153,20 @@ void main()
 			const Vec3 rayDir = toLight / distanceToLight; // normalize
 
 			const F32 lambertTerm = dot(rayDir, normal);
+			F32 shadowFactor;
 			ANKI_BRANCH if(lambertTerm > 0.0)
 			{
-				shadowFactors[light.m_shadowLayer] = trace(worldPos, rayDir, distanceToLight);
+				shadowFactor = trace(worldPos, rayDir, distanceToLight);
+			}
+			else
+			{
+				shadowFactor = 0.0;
 			}
+
+			shadowFactors[light.m_shadowLayer] = shadowFactor;
 		}
 	}
 
-	Vec4 shadowFactors0 = Vec4(shadowFactors[0], shadowFactors[1], shadowFactors[2], shadowFactors[3]);
-	Vec4 shadowFactors1 = Vec4(shadowFactors[4], shadowFactors[5], shadowFactors[6], shadowFactors[7]);
-
 	// Do temporal accumulation
 	{
 		const Vec2 historyUv = uv + textureLod(u_motionVectorsRt, u_linearAnyClampSampler, uv, 0.0).rg;
@@ -155,16 +176,29 @@ void main()
 		const F32 nominalBlendFactor = 0.1;
 		const F32 blendFactor = mix(nominalBlendFactor, 1.0, rejectionFactor);
 
-		// Sample and blend with history
-		const Vec4 history0 = textureLod(u_historyRt, u_linearAnyClampSampler, Vec3(historyUv, 0.0), 0.0);
-		const Vec4 history1 = textureLod(u_historyRt, u_linearAnyClampSampler, Vec3(historyUv, 1.0), 0.0);
+		// Blend with history
+		for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
+		{
+			ANKI_BRANCH if(shadowFactors[i] != -1.0)
+			{
+				// Inside the area of influence of the light and it's an active layer, blend with history
 
-		shadowFactors0 = mix(history0, shadowFactors0, min(Vec4(1.0), u_historyRejectFactor0 + blendFactor));
-		shadowFactors1 = mix(history1, shadowFactors1, min(Vec4(1.0), u_historyRejectFactor1 + blendFactor));
+				const F32 w = (F32(i) + 0.5) / F32(MAX_RT_SHADOW_LAYERS);
+				const F32 history = textureLod(u_historyRt, u_linearAnyClampSampler, Vec3(historyUv, w), 0.0).r;
+				shadowFactors[i] =
+					mix(history, shadowFactors[i], min(1.0, u_unis.historyRejectFactor[i] + blendFactor));
+			}
+		}
 	}
 
 	// Store
-	imageStore(u_outImg[0], IVec2(gl_LaunchIDEXT.xy), shadowFactors0);
-	imageStore(u_outImg[1], IVec2(gl_LaunchIDEXT.xy), shadowFactors1);
+	ANKI_UNROLL for(U32 i = 0; i < MAX_RT_SHADOW_LAYERS; ++i)
+	{
+		if((u_unis.activeShadowLayerMask & (1 << i)) != 0)
+		{
+			const F32 storeValue = max(shadowFactors[i], 0.0);
+			imageStore(u_outImg, IVec3(gl_LaunchIDEXT.xy, i), Vec4(storeValue));
+		}
+	}
 }
 #pragma anki end

+ 12 - 0
AnKi/Shaders/SvgfAtrous.ankiprog

@@ -0,0 +1,12 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki start comp
+
+void main()
+{
+}
+
+#pragma anki end

+ 0 - 49
AnKi/Shaders/SvgfTemporal.ankiprog

@@ -3,59 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-// Part of SVGF. It reprojects and accumulates the input image and computes its moments
-
-#pragma anki mutator INPUT_TEXTURE_COMPONENTS 1 3 // 1: for shadows, 3: for any other HDR color value
-
-ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 2, UVec2(1));
-
 #pragma anki start comp
-#include <AnKi/Shaders/Functions.glsl>
-
-const UVec2 WORKGROUP_SIZE = UVec2(8, 8);
-layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
-layout(set = 0, binding = 1) uniform texture2D u_motionVectorsTex;
-layout(set = 0, binding = 2) uniform texture2D u_currentInputTex;
-layout(set = 0, binding = 3) uniform texture2D u_historyInputTex;
-layout(set = 0, binding = 4) uniform texture2D u_historyMomentsTex;
-layout(set = 0, binding = 5) uniform writeonly image2D u_outputImage;
-layout(set = 0, binding = 6) uniform writeonly image2D u_outputMomentsImage;
 
 void main()
 {
-	if((FB_SIZE.x % WORKGROUP_SIZE.x) != 0u || (FB_SIZE.y % WORKGROUP_SIZE.y) != 0u) // This check is free
-	{
-		if(gl_GlobalInvocationID.x >= FB_SIZE.x || gl_GlobalInvocationID.y >= FB_SIZE.y)
-		{
-			return;
-		}
-	}
-
-	// Get UVs
-	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(FB_SIZE);
-	const Vec3 motionVecs = textureLod(u_motionVectorsTex, u_linearAnyClampSampler, uv, 0.0).rg;
-	const Vec2 historyUv = uv + motionVecs.xy;
-	const F32 rejectionFactor = motionVecs.z;
-
-	// Blend current and hitory
-	const F32 nominalBlendFactor = 0.1;
-	const F32 blendFactor = mix(nominalBlendFactor, 1.0, rejectionFactor);
-
-	const Vec3 current = textureLod(u_currentInputTex, u_linearAnyClampSampler, uv, 0.0)
-#if INPUT_TEXTURE_COMPONENTS == 1
-							 .rrr;
-#else
-							 .rgb;
-#endif
-
-	const Vec3 history = textureLod(u_historyInputTex, u_linearAnyClampSampler, historyUv, 0.0)
-#if INPUT_TEXTURE_COMPONENTS == 1
-							 .rrr;
-#else
-							 .rgb;
-#endif
 }
 
 #pragma anki end

+ 12 - 0
AnKi/Shaders/SvgfVariance.ankiprog

@@ -0,0 +1,12 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki start comp
+
+void main()
+{
+}
+
+#pragma anki end

+ 0 - 3
Sandbox/config.xml

@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<config>
-</config>