Browse Source

Merge pull request #87 from godlikepanos/gi_opts

Gi opts
Panagiotis Christopoulos Charitos 4 years ago
parent
commit
ca52eafc3d
38 changed files with 869 additions and 1546 deletions
  1. 2 4
      AnKi/Renderer.h
  2. 4 0
      AnKi/Renderer/ConfigDefs.h
  3. 0 1
      AnKi/Renderer/FinalComposite.cpp
  4. 205 0
      AnKi/Renderer/IndirectDiffuse.cpp
  5. 82 0
      AnKi/Renderer/IndirectDiffuse.h
  6. 22 22
      AnKi/Renderer/IndirectDiffuseProbes.cpp
  7. 3 3
      AnKi/Renderer/IndirectDiffuseProbes.h
  8. 64 33
      AnKi/Renderer/LightShading.cpp
  9. 8 0
      AnKi/Renderer/LightShading.h
  10. 2 7
      AnKi/Renderer/MotionVectors.cpp
  11. 16 17
      AnKi/Renderer/Renderer.cpp
  12. 2 3
      AnKi/Renderer/RendererObjectDefs.h
  13. 0 259
      AnKi/Renderer/Ssao.cpp
  14. 0 90
      AnKi/Renderer/Ssao.h
  15. 0 277
      AnKi/Renderer/Ssgi.cpp
  16. 0 93
      AnKi/Renderer/Ssgi.h
  17. 3 3
      AnKi/Renderer/VolumetricLightingAccumulation.cpp
  18. 1 0
      AnKi/ShaderCompiler/ShaderProgramParser.cpp
  19. 1 1
      AnKi/Shaders/ImportanceSampling.glsl
  20. 18 2
      AnKi/Shaders/Include/ClusteredShadingTypes.h
  21. 34 0
      AnKi/Shaders/Include/IndirectDiffuseTypes.h
  22. 216 0
      AnKi/Shaders/IndirectDiffuse.ankiprog
  23. 88 0
      AnKi/Shaders/IndirectDiffuseDenoise.ankiprog
  24. 1 1
      AnKi/Shaders/IrradianceDice.ankiprog
  25. 10 65
      AnKi/Shaders/LightShading.ankiprog
  26. 58 0
      AnKi/Shaders/LightShadingApplyIndirect.ankiprog
  27. 20 11
      AnKi/Shaders/SsRaymarching.glsl
  28. 0 12
      AnKi/Shaders/Ssao.ankiprog
  29. 0 226
      AnKi/Shaders/Ssao.glsl
  30. 0 8
      AnKi/Shaders/SsaoCompute.ankiprog
  31. 0 156
      AnKi/Shaders/Ssgi.ankiprog
  32. 0 124
      AnKi/Shaders/SsgiDenoise.ankiprog
  33. 0 125
      AnKi/Shaders/SsgiReconstruct.ankiprog
  34. 1 1
      AnKi/Shaders/VisualizeRenderTarget.ankiprog
  35. 2 1
      Samples/Common/Framework.cpp
  36. 2 0
      Samples/Sponza/GenerateAndroidProject.bat
  37. 2 1
      Sandbox/Main.cpp
  38. 2 0
      Tests/GenerateAndroidProject.bat

+ 2 - 4
AnKi/Renderer.h

@@ -20,19 +20,17 @@
 #include <AnKi/Renderer/TemporalAA.h>
 #include <AnKi/Renderer/TemporalAA.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/Ssr.h>
-#include <AnKi/Renderer/Ssgi.h>
 #include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Renderer/Dbg.h>
 #include <AnKi/Renderer/Dbg.h>
-#include <AnKi/Renderer/Ssao.h>
-#include <AnKi/Renderer/Ssgi.h>
 #include <AnKi/Renderer/Drawer.h>
 #include <AnKi/Renderer/Drawer.h>
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/Tonemapping.h>
 #include <AnKi/Renderer/Tonemapping.h>
 #include <AnKi/Renderer/RendererObject.h>
 #include <AnKi/Renderer/RendererObject.h>
 #include <AnKi/Renderer/Bloom.h>
 #include <AnKi/Renderer/Bloom.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
-#include <AnKi/Renderer/GlobalIllumination.h>
+#include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/GenericCompute.h>
 #include <AnKi/Renderer/GenericCompute.h>
 #include <AnKi/Renderer/ShadowmapsResolve.h>
 #include <AnKi/Renderer/ShadowmapsResolve.h>
+#include <AnKi/Renderer/IndirectDiffuse.h>
 
 
 /// @defgroup renderer Renderering system
 /// @defgroup renderer Renderering system

+ 4 - 0
AnKi/Renderer/ConfigDefs.h

@@ -22,6 +22,10 @@ ANKI_CONFIG_OPTION(r_ssrDepthLod, 2, 0, 1000)
 ANKI_CONFIG_OPTION(r_ssgiMaxSteps, 32, 1, 2048)
 ANKI_CONFIG_OPTION(r_ssgiMaxSteps, 32, 1, 2048)
 ANKI_CONFIG_OPTION(r_ssgiDepthLod, 2, 0, 1000)
 ANKI_CONFIG_OPTION(r_ssgiDepthLod, 2, 0, 1000)
 
 
+ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiSamples, 8, 1, 1024)
+ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiRadius, 2.0, 0.1, 100.0)
+ANKI_CONFIG_OPTION(r_indirectDiffuseDenoiseSampleCount, 4, 1, 128)
+
 ANKI_CONFIG_OPTION(r_shadowMappingTileResolution, 128, 16, 2048)
 ANKI_CONFIG_OPTION(r_shadowMappingTileResolution, 128, 16, 2048)
 ANKI_CONFIG_OPTION(r_shadowMappingTileCountPerRowOrColumn, 16, 1, 256)
 ANKI_CONFIG_OPTION(r_shadowMappingTileCountPerRowOrColumn, 16, 1, 256)
 ANKI_CONFIG_OPTION(r_shadowMappingScratchTileCountX, 4 * (MAX_SHADOW_CASCADES2 + 2), 1u, 256u,
 ANKI_CONFIG_OPTION(r_shadowMappingScratchTileCountX, 4 * (MAX_SHADOW_CASCADES2 + 2), 1u, 256u,

+ 0 - 1
AnKi/Renderer/FinalComposite.cpp

@@ -11,7 +11,6 @@
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/Dbg.h>
 #include <AnKi/Renderer/Dbg.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/DownscaleBlur.h>
 #include <AnKi/Renderer/DownscaleBlur.h>
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/UiStage.h>

+ 205 - 0
AnKi/Renderer/IndirectDiffuse.cpp

@@ -0,0 +1,205 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Renderer/IndirectDiffuse.h>
+#include <AnKi/Renderer/Renderer.h>
+#include <AnKi/Renderer/DepthDownscale.h>
+#include <AnKi/Renderer/GBuffer.h>
+#include <AnKi/Renderer/DownscaleBlur.h>
+#include <AnKi/Renderer/MotionVectors.h>
+#include <AnKi/Renderer/IndirectDiffuseProbes.h>
+#include <AnKi/Core/ConfigSet.h>
+#include <AnKi/Shaders/Include/IndirectDiffuseTypes.h>
+
+namespace anki
+{
+
+IndirectDiffuse::~IndirectDiffuse()
+{
+}
+
+Error IndirectDiffuse::init(const ConfigSet& cfg)
+{
+	const Error err = initInternal(cfg);
+	if(err)
+	{
+		ANKI_R_LOGE("Failed to initialize indirect diffuse pass");
+	}
+	return err;
+}
+
+Error IndirectDiffuse::initInternal(const ConfigSet& cfg)
+{
+	const UVec2 size = m_r->getInternalResolution() / 2;
+	ANKI_ASSERT((m_r->getInternalResolution() % 2) == UVec2(0u) && "Needs to be dividable for proper upscaling");
+
+	// Init textures
+	TextureInitInfo texInit = m_r->create2DRenderTargetInitInfo(
+		size.x(), size.y(), Format::B10G11R11_UFLOAT_PACK32,
+		TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::ALL_SAMPLED, "IndirectDiffuse #1");
+	texInit.m_initialUsage = TextureUsageBit::ALL_SAMPLED;
+	m_rts[0] = m_r->createAndClearRenderTarget(texInit);
+	texInit.setName("IndirectDiffuse #2");
+	m_rts[1] = m_r->createAndClearRenderTarget(texInit);
+
+	// Init SSGI+probes pass
+	{
+		m_main.m_radius = cfg.getNumberF32("r_indirectDiffuseSsgiRadius");
+		m_main.m_sampleCount = cfg.getNumberU32("r_indirectDiffuseSsgiSamples");
+
+		ANKI_CHECK(getResourceManager().loadResource("Shaders/IndirectDiffuse.ankiprog", m_main.m_prog));
+
+		const ShaderProgramResourceVariant* variant;
+		m_main.m_prog->getOrCreateVariant(variant);
+		m_main.m_grProg = variant->getProgram();
+	}
+
+	// Init denoise
+	{
+		m_denoise.m_sampleCount = F32(cfg.getNumberU32("r_indirectDiffuseDenoiseSampleCount"));
+		m_denoise.m_sampleCount = max(1.0f, std::round(m_denoise.m_sampleCount / 2.0f));
+
+		ANKI_CHECK(getResourceManager().loadResource("Shaders/IndirectDiffuseDenoise.ankiprog", m_denoise.m_prog));
+
+		ShaderProgramResourceVariantInitInfo variantInit(m_denoise.m_prog);
+		variantInit.addMutation("BLUR_ORIENTATION", 0);
+		const ShaderProgramResourceVariant* variant;
+		m_denoise.m_prog->getOrCreateVariant(variantInit, variant);
+		m_denoise.m_grProgs[0] = variant->getProgram();
+
+		variantInit.addMutation("BLUR_ORIENTATION", 1);
+		m_denoise.m_prog->getOrCreateVariant(variantInit, variant);
+		m_denoise.m_grProgs[1] = variant->getProgram();
+	}
+
+	return Error::NONE;
+}
+
+void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
+{
+	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
+
+	// SSGI+probes
+	{
+		// Create RTs
+		const U32 readRtIdx = m_r->getFrameCount() & 1;
+		const U32 writeRtIdx = !readRtIdx;
+		if(ANKI_LIKELY(m_rtsImportedOnce))
+		{
+			m_runCtx.m_mainRtHandles[0] = rgraph.importRenderTarget(m_rts[readRtIdx]);
+			m_runCtx.m_mainRtHandles[1] = rgraph.importRenderTarget(m_rts[writeRtIdx]);
+		}
+		else
+		{
+			m_runCtx.m_mainRtHandles[0] = rgraph.importRenderTarget(m_rts[readRtIdx], TextureUsageBit::ALL_SAMPLED);
+			m_runCtx.m_mainRtHandles[1] = rgraph.importRenderTarget(m_rts[writeRtIdx], TextureUsageBit::ALL_SAMPLED);
+			m_rtsImportedOnce = true;
+		}
+
+		// Create main pass
+		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("IndirectDiffuse");
+
+		rpass.newDependency(
+			RenderPassDependency(m_runCtx.m_mainRtHandles[WRITE], TextureUsageBit::IMAGE_COMPUTE_WRITE));
+
+		const TextureUsageBit readUsage = TextureUsageBit::SAMPLED_COMPUTE;
+		m_r->getIndirectDiffuseProbes().setRenderGraphDependencies(ctx, rpass, readUsage);
+		rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(2), readUsage));
+		TextureSubresourceInfo hizSubresource;
+		hizSubresource.m_mipmapCount = 1;
+		rpass.newDependency(RenderPassDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, hizSubresource));
+		rpass.newDependency(RenderPassDependency(m_r->getDownscaleBlur().getRt(), readUsage));
+		rpass.newDependency(RenderPassDependency(m_r->getMotionVectors().getMotionVectorsRt(), readUsage));
+		rpass.newDependency(RenderPassDependency(m_r->getMotionVectors().getRejectionFactorRt(), readUsage));
+		rpass.newDependency(RenderPassDependency(m_runCtx.m_mainRtHandles[READ], readUsage));
+
+		rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
+			CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+			cmdb->bindShaderProgram(m_main.m_grProg);
+
+			const ClusteredShadingContext& binning = ctx.m_clusteredShading;
+			bindUniforms(cmdb, 0, 0, binning.m_clusteredShadingUniformsToken);
+			m_r->getIndirectDiffuseProbes().bindVolumeTextures(ctx, rgraphCtx, 0, 1);
+			bindUniforms(cmdb, 0, 2, binning.m_globalIlluminationProbesToken);
+			bindStorage(cmdb, 0, 3, binning.m_clustersToken);
+
+			rgraphCtx.bindImage(0, 4, m_runCtx.m_mainRtHandles[WRITE]);
+
+			cmdb->bindSampler(0, 5, m_r->getSamplers().m_trilinearClamp);
+			rgraphCtx.bindColorTexture(0, 6, m_r->getGBuffer().getColorRt(2));
+
+			TextureSubresourceInfo hizSubresource;
+			hizSubresource.m_mipmapCount = 1;
+			rgraphCtx.bindTexture(0, 7, m_r->getDepthDownscale().getHiZRt(), hizSubresource);
+			rgraphCtx.bindColorTexture(0, 8, m_r->getDownscaleBlur().getRt());
+			rgraphCtx.bindColorTexture(0, 9, m_runCtx.m_mainRtHandles[READ]);
+			rgraphCtx.bindColorTexture(0, 10, m_r->getMotionVectors().getMotionVectorsRt());
+			rgraphCtx.bindColorTexture(0, 11, m_r->getMotionVectors().getRejectionFactorRt());
+
+			// Bind uniforms
+			IndirectDiffuseUniforms unis;
+			unis.m_viewportSize = m_r->getInternalResolution() / 2u;
+			unis.m_viewportSizef = Vec2(unis.m_viewportSize);
+			const Mat4& pmat = ctx.m_matrices.m_projection;
+			unis.m_projectionMat = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
+			unis.m_radius = m_main.m_radius;
+			unis.m_sampleCount = m_main.m_sampleCount;
+			unis.m_sampleCountf = F32(m_main.m_sampleCount);
+			unis.m_ssaoBias = m_main.m_ssaoBias;
+			unis.m_ssaoStrength = m_main.m_ssaoStrength;
+			cmdb->setPushConstants(&unis, sizeof(unis));
+
+			// Dispatch
+			dispatchPPCompute(cmdb, 8, 8, unis.m_viewportSize.x(), unis.m_viewportSize.y());
+		});
+	}
+
+	// Denoise
+	for(U32 dir = 0; dir < 2; ++dir)
+	{
+		ComputeRenderPassDescription& rpass =
+			rgraph.newComputeRenderPass((dir == 0) ? "IndirectDiffuseDenoiseH" : "IndirectDiffuseDenoiseV");
+
+		const TextureUsageBit readUsage = TextureUsageBit::SAMPLED_COMPUTE;
+		const U32 readIdx = (dir == 0) ? WRITE : READ;
+
+		rpass.newDependency(RenderPassDependency(m_runCtx.m_mainRtHandles[readIdx], readUsage));
+
+		TextureSubresourceInfo hizSubresource;
+		hizSubresource.m_mipmapCount = 1;
+		rpass.newDependency(RenderPassDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, hizSubresource));
+
+		rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(2), readUsage));
+
+		rpass.newDependency(
+			RenderPassDependency(m_runCtx.m_mainRtHandles[!readIdx], TextureUsageBit::IMAGE_COMPUTE_WRITE));
+
+		rpass.setWork([this, &ctx, dir, readIdx](RenderPassWorkContext& rgraphCtx) {
+			CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+			cmdb->bindShaderProgram(m_denoise.m_grProgs[dir]);
+
+			cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
+			rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_mainRtHandles[readIdx]);
+			TextureSubresourceInfo hizSubresource;
+			hizSubresource.m_mipmapCount = 1;
+			rgraphCtx.bindTexture(0, 2, m_r->getDepthDownscale().getHiZRt(), hizSubresource);
+			rgraphCtx.bindColorTexture(0, 3, m_r->getGBuffer().getColorRt(2));
+			rgraphCtx.bindImage(0, 4, m_runCtx.m_mainRtHandles[!readIdx]);
+
+			IndirectDiffuseDenoiseUniforms unis;
+			unis.m_invertedViewProjectionJitterMat = ctx.m_matrices.m_invertedViewProjectionJitter;
+			unis.m_viewportSize = m_r->getInternalResolution() / 2u;
+			unis.m_viewportSizef = Vec2(unis.m_viewportSize);
+			unis.m_sampleCountDiv2 = m_denoise.m_sampleCount;
+
+			cmdb->setPushConstants(&unis, sizeof(unis));
+
+			// Dispatch
+			dispatchPPCompute(cmdb, 8, 8, unis.m_viewportSize.x(), unis.m_viewportSize.y());
+		});
+	}
+}
+
+} // end namespace anki

+ 82 - 0
AnKi/Renderer/IndirectDiffuse.h

@@ -0,0 +1,82 @@
+// 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/Renderer/RendererObject.h>
+#include <AnKi/Resource/ImageResource.h>
+#include <AnKi/Gr.h>
+
+namespace anki
+{
+
+/// @addtogroup renderer
+/// @{
+
+/// Global illumination.
+class IndirectDiffuse : public RendererObject
+{
+public:
+	IndirectDiffuse(Renderer* r)
+		: RendererObject(r)
+	{
+		registerDebugRenderTarget("IndirectDiffuse");
+	}
+
+	~IndirectDiffuse();
+
+	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
+
+	void populateRenderGraph(RenderingContext& ctx);
+
+	void getDebugRenderTarget(CString rtName, RenderTargetHandle& handle,
+							  ShaderProgramPtr& optionalShaderProgram) const override
+	{
+		ANKI_ASSERT(rtName == "IndirectDiffuse");
+		handle = m_runCtx.m_mainRtHandles[WRITE];
+	}
+
+	RenderTargetHandle getRt() const
+	{
+		return m_runCtx.m_mainRtHandles[WRITE];
+	}
+
+private:
+	Array<TexturePtr, 2> m_rts;
+	Bool m_rtsImportedOnce = false;
+
+	static constexpr U32 READ = 0;
+	static constexpr U32 WRITE = 1;
+
+	class
+	{
+	public:
+		ShaderProgramResourcePtr m_prog;
+		ShaderProgramPtr m_grProg;
+		F32 m_radius;
+		U32 m_sampleCount = 8.0f;
+		F32 m_ssaoStrength = 2.5f;
+		F32 m_ssaoBias = -0.1f;
+	} m_main;
+
+	class
+	{
+	public:
+		ShaderProgramResourcePtr m_prog;
+		Array<ShaderProgramPtr, 2> m_grProgs;
+		F32 m_sampleCount = 1.0f;
+	} m_denoise;
+
+	class
+	{
+	public:
+		Array<RenderTargetHandle, 2> m_mainRtHandles;
+	} m_runCtx;
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
+};
+/// @}
+
+} // namespace anki

+ 22 - 22
AnKi/Renderer/GlobalIllumination.cpp → AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -3,7 +3,7 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#include <AnKi/Renderer/GlobalIllumination.h>
+#include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Core/ConfigSet.h>
@@ -30,10 +30,10 @@ static Vec3 computeProbeCellPosition(U32 cellIdx, const GlobalIlluminationProbeQ
 	return cellPos;
 	return cellPos;
 }
 }
 
 
-class GlobalIllumination::InternalContext
+class IndirectDiffuseProbes::InternalContext
 {
 {
 public:
 public:
-	GlobalIllumination* m_gi ANKI_DEBUG_CODE(= numberToPtr<GlobalIllumination*>(1));
+	IndirectDiffuseProbes* m_gi ANKI_DEBUG_CODE(= numberToPtr<IndirectDiffuseProbes*>(1));
 	RenderingContext* m_ctx ANKI_DEBUG_CODE(= numberToPtr<RenderingContext*>(1));
 	RenderingContext* m_ctx ANKI_DEBUG_CODE(= numberToPtr<RenderingContext*>(1));
 
 
 	GlobalIlluminationProbeQueueElement*
 	GlobalIlluminationProbeQueueElement*
@@ -55,14 +55,14 @@ public:
 	}
 	}
 };
 };
 
 
-GlobalIllumination::~GlobalIllumination()
+IndirectDiffuseProbes::~IndirectDiffuseProbes()
 {
 {
 	m_cacheEntries.destroy(getAllocator());
 	m_cacheEntries.destroy(getAllocator());
 	m_probeUuidToCacheEntryIdx.destroy(getAllocator());
 	m_probeUuidToCacheEntryIdx.destroy(getAllocator());
 }
 }
 
 
 const RenderTargetHandle&
 const RenderTargetHandle&
-GlobalIllumination::getVolumeRenderTarget(const GlobalIlluminationProbeQueueElement& probe) const
+IndirectDiffuseProbes::getVolumeRenderTarget(const GlobalIlluminationProbeQueueElement& probe) const
 {
 {
 	ANKI_ASSERT(m_giCtx);
 	ANKI_ASSERT(m_giCtx);
 	ANKI_ASSERT(&probe >= &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getFront()
 	ANKI_ASSERT(&probe >= &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getFront()
@@ -71,8 +71,8 @@ GlobalIllumination::getVolumeRenderTarget(const GlobalIlluminationProbeQueueElem
 	return m_giCtx->m_irradianceProbeRts[idx];
 	return m_giCtx->m_irradianceProbeRts[idx];
 }
 }
 
 
-void GlobalIllumination::setRenderGraphDependencies(const RenderingContext& ctx, RenderPassDescriptionBase& pass,
-													TextureUsageBit usage) const
+void IndirectDiffuseProbes::setRenderGraphDependencies(const RenderingContext& ctx, RenderPassDescriptionBase& pass,
+													   TextureUsageBit usage) const
 {
 {
 	for(U32 idx = 0; idx < ctx.m_renderQueue->m_giProbes.getSize(); ++idx)
 	for(U32 idx = 0; idx < ctx.m_renderQueue->m_giProbes.getSize(); ++idx)
 	{
 	{
@@ -80,8 +80,8 @@ void GlobalIllumination::setRenderGraphDependencies(const RenderingContext& ctx,
 	}
 	}
 }
 }
 
 
-void GlobalIllumination::bindVolumeTextures(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx, U32 set,
-											U32 binding) const
+void IndirectDiffuseProbes::bindVolumeTextures(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx, U32 set,
+											   U32 binding) const
 {
 {
 	for(U32 idx = 0; idx < MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES; ++idx)
 	for(U32 idx = 0; idx < MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES; ++idx)
 	{
 	{
@@ -96,7 +96,7 @@ void GlobalIllumination::bindVolumeTextures(const RenderingContext& ctx, RenderP
 	}
 	}
 }
 }
 
 
-Error GlobalIllumination::init(const ConfigSet& cfg)
+Error IndirectDiffuseProbes::init(const ConfigSet& cfg)
 {
 {
 	ANKI_R_LOGI("Initializing global illumination");
 	ANKI_R_LOGI("Initializing global illumination");
 
 
@@ -109,7 +109,7 @@ Error GlobalIllumination::init(const ConfigSet& cfg)
 	return err;
 	return err;
 }
 }
 
 
-Error GlobalIllumination::initInternal(const ConfigSet& cfg)
+Error IndirectDiffuseProbes::initInternal(const ConfigSet& cfg)
 {
 {
 	m_tileSize = cfg.getNumberU32("r_giTileResolution");
 	m_tileSize = cfg.getNumberU32("r_giTileResolution");
 	m_cacheEntries.create(getAllocator(), cfg.getNumberU32("r_giMaxCachedProbes"));
 	m_cacheEntries.create(getAllocator(), cfg.getNumberU32("r_giMaxCachedProbes"));
@@ -125,7 +125,7 @@ Error GlobalIllumination::initInternal(const ConfigSet& cfg)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error GlobalIllumination::initGBuffer(const ConfigSet& cfg)
+Error IndirectDiffuseProbes::initGBuffer(const ConfigSet& cfg)
 {
 {
 	// Create RT descriptions
 	// Create RT descriptions
 	{
 	{
@@ -167,7 +167,7 @@ Error GlobalIllumination::initGBuffer(const ConfigSet& cfg)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error GlobalIllumination::initShadowMapping(const ConfigSet& cfg)
+Error IndirectDiffuseProbes::initShadowMapping(const ConfigSet& cfg)
 {
 {
 	const U32 resolution = cfg.getNumberU32("r_giShadowMapResolution");
 	const U32 resolution = cfg.getNumberU32("r_giShadowMapResolution");
 	ANKI_ASSERT(resolution > 8);
 	ANKI_ASSERT(resolution > 8);
@@ -197,7 +197,7 @@ Error GlobalIllumination::initShadowMapping(const ConfigSet& cfg)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error GlobalIllumination::initLightShading(const ConfigSet& cfg)
+Error IndirectDiffuseProbes::initLightShading(const ConfigSet& cfg)
 {
 {
 	// Init RT descr
 	// Init RT descr
 	{
 	{
@@ -219,7 +219,7 @@ Error GlobalIllumination::initLightShading(const ConfigSet& cfg)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error GlobalIllumination::initIrradiance(const ConfigSet& cfg)
+Error IndirectDiffuseProbes::initIrradiance(const ConfigSet& cfg)
 {
 {
 	ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/IrradianceDice.ankiprog", m_irradiance.m_prog));
 	ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/IrradianceDice.ankiprog", m_irradiance.m_prog));
 
 
@@ -236,7 +236,7 @@ Error GlobalIllumination::initIrradiance(const ConfigSet& cfg)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
+void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
 
@@ -382,7 +382,7 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 	}
 	}
 }
 }
 
 
-void GlobalIllumination::prepareProbes(InternalContext& giCtx)
+void IndirectDiffuseProbes::prepareProbes(InternalContext& giCtx)
 {
 {
 	RenderingContext& ctx = *giCtx.m_ctx;
 	RenderingContext& ctx = *giCtx.m_ctx;
 	giCtx.m_probeToUpdateThisFrame = nullptr;
 	giCtx.m_probeToUpdateThisFrame = nullptr;
@@ -484,7 +484,7 @@ void GlobalIllumination::prepareProbes(InternalContext& giCtx)
 		const Bool shouldInitTextures = !entry.m_volumeTex.isCreated() || entry.m_volumeSize != probe.m_cellCounts;
 		const Bool shouldInitTextures = !entry.m_volumeTex.isCreated() || entry.m_volumeSize != probe.m_cellCounts;
 		if(shouldInitTextures)
 		if(shouldInitTextures)
 		{
 		{
-			TextureInitInfo texInit;
+			TextureInitInfo texInit("GiProbeVolume");
 			texInit.m_type = TextureType::_3D;
 			texInit.m_type = TextureType::_3D;
 			texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
 			texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
 			texInit.m_width = probe.m_cellCounts.x() * 6;
 			texInit.m_width = probe.m_cellCounts.x() * 6;
@@ -545,7 +545,7 @@ void GlobalIllumination::prepareProbes(InternalContext& giCtx)
 	}
 	}
 }
 }
 
 
-void GlobalIllumination::runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
+void IndirectDiffuseProbes::runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
 {
 {
 	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
@@ -590,7 +590,7 @@ void GlobalIllumination::runGBufferInThread(RenderPassWorkContext& rgraphCtx, In
 	// It's secondary, no need to restore the state
 	// It's secondary, no need to restore the state
 }
 }
 
 
-void GlobalIllumination::runShadowmappingInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
+void IndirectDiffuseProbes::runShadowmappingInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
 {
 {
 	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
@@ -639,7 +639,7 @@ void GlobalIllumination::runShadowmappingInThread(RenderPassWorkContext& rgraphC
 	// It's secondary, no need to restore the state
 	// It's secondary, no need to restore the state
 }
 }
 
 
-void GlobalIllumination::runLightShading(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
+void IndirectDiffuseProbes::runLightShading(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
 
@@ -699,7 +699,7 @@ void GlobalIllumination::runLightShading(RenderPassWorkContext& rgraphCtx, Inter
 	}
 	}
 }
 }
 
 
-void GlobalIllumination::runIrradiance(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
+void IndirectDiffuseProbes::runIrradiance(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
 

+ 3 - 3
AnKi/Renderer/GlobalIllumination.h → AnKi/Renderer/IndirectDiffuseProbes.h

@@ -19,16 +19,16 @@ namespace anki
 /// Ambient global illumination passes.
 /// Ambient global illumination passes.
 ///
 ///
 /// It builds a volume clipmap with ambient GI information.
 /// It builds a volume clipmap with ambient GI information.
-class GlobalIllumination : public RendererObject
+class IndirectDiffuseProbes : public RendererObject
 {
 {
 public:
 public:
-	GlobalIllumination(Renderer* r)
+	IndirectDiffuseProbes(Renderer* r)
 		: RendererObject(r)
 		: RendererObject(r)
 		, m_lightShading(r)
 		, m_lightShading(r)
 	{
 	{
 	}
 	}
 
 
-	~GlobalIllumination();
+	~IndirectDiffuseProbes();
 
 
 	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
 
 

+ 64 - 33
AnKi/Renderer/LightShading.cpp

@@ -12,12 +12,10 @@
 #include <AnKi/Renderer/ForwardShading.h>
 #include <AnKi/Renderer/ForwardShading.h>
 #include <AnKi/Renderer/VolumetricFog.h>
 #include <AnKi/Renderer/VolumetricFog.h>
 #include <AnKi/Renderer/DepthDownscale.h>
 #include <AnKi/Renderer/DepthDownscale.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/Ssr.h>
-#include <AnKi/Renderer/Ssgi.h>
-#include <AnKi/Renderer/GlobalIllumination.h>
 #include <AnKi/Renderer/ShadowmapsResolve.h>
 #include <AnKi/Renderer/ShadowmapsResolve.h>
 #include <AnKi/Renderer/RtShadows.h>
 #include <AnKi/Renderer/RtShadows.h>
+#include <AnKi/Renderer/IndirectDiffuse.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Util/HighRezTimer.h>
 #include <AnKi/Util/HighRezTimer.h>
 
 
@@ -43,6 +41,11 @@ Error LightShading::init(const ConfigSet& config)
 		err = initApplyFog(config);
 		err = initApplyFog(config);
 	}
 	}
 
 
+	if(!err)
+	{
+		err = initApplyIndirect(config);
+	}
+
 	if(err)
 	if(err)
 	{
 	{
 		ANKI_R_LOGE("Failed to init light stage");
 		ANKI_R_LOGE("Failed to init light stage");
@@ -104,6 +107,15 @@ Error LightShading::initApplyFog(const ConfigSet& config)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
+Error LightShading::initApplyIndirect(const ConfigSet& config)
+{
+	ANKI_CHECK(getResourceManager().loadResource("Shaders/LightShadingApplyIndirect.ankiprog", m_applyIndirect.m_prog));
+	const ShaderProgramResourceVariant* variant;
+	m_applyIndirect.m_prog->getOrCreateVariant(variant);
+	m_applyIndirect.m_grProg = variant->getProgram();
+	return Error::NONE;
+}
+
 void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
 void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
 {
 {
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
@@ -128,35 +140,55 @@ void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgrap
 		rgraphCtx.bindColorTexture(0, 5, m_r->getProbeReflections().getReflectionRt());
 		rgraphCtx.bindColorTexture(0, 5, m_r->getProbeReflections().getReflectionRt());
 		cmdb->bindTexture(0, 6, m_r->getProbeReflections().getIntegrationLut());
 		cmdb->bindTexture(0, 6, m_r->getProbeReflections().getIntegrationLut());
 
 
-		m_r->getGlobalIllumination().bindVolumeTextures(ctx, rgraphCtx, 0, 7);
-		bindUniforms(cmdb, 0, 8, binning.m_globalIlluminationProbesToken);
+		bindStorage(cmdb, 0, 7, binning.m_clustersToken);
 
 
-		bindStorage(cmdb, 0, 9, binning.m_clustersToken);
-
-		cmdb->bindSampler(0, 10, m_r->getSamplers().m_nearestNearestClamp);
-		cmdb->bindSampler(0, 11, m_r->getSamplers().m_trilinearClamp);
-		rgraphCtx.bindColorTexture(0, 12, m_r->getGBuffer().getColorRt(0));
-		rgraphCtx.bindColorTexture(0, 13, m_r->getGBuffer().getColorRt(1));
-		rgraphCtx.bindColorTexture(0, 14, m_r->getGBuffer().getColorRt(2));
-		rgraphCtx.bindTexture(0, 15, m_r->getGBuffer().getDepthRt(),
+		cmdb->bindSampler(0, 8, m_r->getSamplers().m_nearestNearestClamp);
+		cmdb->bindSampler(0, 9, m_r->getSamplers().m_trilinearClamp);
+		rgraphCtx.bindColorTexture(0, 10, m_r->getGBuffer().getColorRt(0));
+		rgraphCtx.bindColorTexture(0, 11, m_r->getGBuffer().getColorRt(1));
+		rgraphCtx.bindColorTexture(0, 12, m_r->getGBuffer().getColorRt(2));
+		rgraphCtx.bindTexture(0, 13, m_r->getGBuffer().getDepthRt(),
 							  TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
 							  TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
-		rgraphCtx.bindColorTexture(0, 16, m_r->getSsr().getRt());
-		rgraphCtx.bindColorTexture(0, 17, m_r->getSsao().getRt());
-		rgraphCtx.bindColorTexture(0, 18, m_r->getSsgi().getRt());
+		rgraphCtx.bindColorTexture(0, 14, m_r->getSsr().getRt());
 
 
 		if(m_r->getRtShadowsEnabled())
 		if(m_r->getRtShadowsEnabled())
 		{
 		{
-			rgraphCtx.bindColorTexture(0, 19, m_r->getRtShadows().getRt());
+			rgraphCtx.bindColorTexture(0, 15, m_r->getRtShadows().getRt());
 		}
 		}
 		else
 		else
 		{
 		{
-			rgraphCtx.bindColorTexture(0, 20, m_r->getShadowmapsResolve().getRt());
+			rgraphCtx.bindColorTexture(0, 16, m_r->getShadowmapsResolve().getRt());
 		}
 		}
 
 
 		// Draw
 		// Draw
 		drawQuad(cmdb);
 		drawQuad(cmdb);
 	}
 	}
 
 
+	// Apply indirect
+	if(rgraphCtx.m_currentSecondLevelCommandBufferIndex == 0)
+	{
+		cmdb->setDepthWrite(false);
+		cmdb->bindShaderProgram(m_applyIndirect.m_grProg);
+
+		cmdb->bindSampler(0, 0, m_r->getSamplers().m_nearestNearestClamp);
+		cmdb->bindSampler(0, 1, m_r->getSamplers().m_trilinearClamp);
+		rgraphCtx.bindColorTexture(0, 2, m_r->getIndirectDiffuse().getRt());
+		rgraphCtx.bindColorTexture(0, 3, m_r->getDepthDownscale().getHiZRt());
+		rgraphCtx.bindTexture(0, 4, m_r->getGBuffer().getDepthRt(),
+							  TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
+		rgraphCtx.bindColorTexture(0, 5, m_r->getGBuffer().getColorRt(0));
+
+		const Vec4 pc(2.0f / Vec2(m_r->getInternalResolution()), 0.0f, 0.0f);
+		cmdb->setPushConstants(&pc, sizeof(pc));
+
+		cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ONE);
+
+		drawQuad(cmdb);
+
+		// Restore state
+		cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ZERO);
+	}
+
 	// Do the fog apply
 	// Do the fog apply
 	if(rgraphCtx.m_currentSecondLevelCommandBufferIndex == rgraphCtx.m_secondLevelCommandBufferCount - 1u)
 	if(rgraphCtx.m_currentSecondLevelCommandBufferIndex == rgraphCtx.m_secondLevelCommandBufferCount - 1u)
 	{
 	{
@@ -209,40 +241,39 @@ void LightShading::populateRenderGraph(RenderingContext& ctx)
 				 [this, &ctx](RenderPassWorkContext& rgraphCtx) { run(ctx, rgraphCtx); });
 				 [this, &ctx](RenderPassWorkContext& rgraphCtx) { run(ctx, rgraphCtx); });
 	pass.setFramebufferInfo(m_lightShading.m_fbDescr, {{m_runCtx.m_rt}}, {m_r->getGBuffer().getDepthRt()});
 	pass.setFramebufferInfo(m_lightShading.m_fbDescr, {{m_runCtx.m_rt}}, {m_r->getGBuffer().getDepthRt()});
 
 
+	const TextureUsageBit readUsage = TextureUsageBit::SAMPLED_FRAGMENT;
+
 	// Light shading
 	// Light shading
 	pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
 	pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
-	pass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(0), TextureUsageBit::SAMPLED_FRAGMENT));
-	pass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(1), TextureUsageBit::SAMPLED_FRAGMENT));
-	pass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_FRAGMENT));
+	pass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(0), readUsage));
+	pass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(1), readUsage));
+	pass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(2), readUsage));
 	pass.newDependency(
 	pass.newDependency(
 		RenderPassDependency(m_r->getGBuffer().getDepthRt(),
 		RenderPassDependency(m_r->getGBuffer().getDepthRt(),
 							 TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ,
 							 TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ,
 							 TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)));
 							 TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)));
-	pass.newDependency(
-		RenderPassDependency(m_r->getShadowMapping().getShadowmapRt(), TextureUsageBit::SAMPLED_FRAGMENT));
-	pass.newDependency(RenderPassDependency(m_r->getSsao().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
-	pass.newDependency(RenderPassDependency(m_r->getSsgi().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+	pass.newDependency(RenderPassDependency(m_r->getShadowMapping().getShadowmapRt(), readUsage));
 	if(m_r->getRtShadowsEnabled())
 	if(m_r->getRtShadowsEnabled())
 	{
 	{
-		pass.newDependency(RenderPassDependency(m_r->getRtShadows().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+		pass.newDependency(RenderPassDependency(m_r->getRtShadows().getRt(), readUsage));
 	}
 	}
 	else
 	else
 	{
 	{
-		pass.newDependency(
-			RenderPassDependency(m_r->getShadowmapsResolve().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+		pass.newDependency(RenderPassDependency(m_r->getShadowmapsResolve().getRt(), readUsage));
 	}
 	}
 	pass.newDependency(
 	pass.newDependency(
 		RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_FRAGMENT_READ));
 		RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_FRAGMENT_READ));
 
 
 	// Refl & indirect
 	// Refl & indirect
-	pass.newDependency(RenderPassDependency(m_r->getSsr().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
-	pass.newDependency(
-		RenderPassDependency(m_r->getProbeReflections().getReflectionRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+	pass.newDependency(RenderPassDependency(m_r->getSsr().getRt(), readUsage));
+	pass.newDependency(RenderPassDependency(m_r->getProbeReflections().getReflectionRt(), readUsage));
 
 
-	m_r->getGlobalIllumination().setRenderGraphDependencies(ctx, pass, TextureUsageBit::SAMPLED_FRAGMENT);
+	// Apply indirect
+	pass.newDependency(RenderPassDependency(m_r->getIndirectDiffuse().getRt(), readUsage));
+	pass.newDependency(RenderPassDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, HIZ_HALF_DEPTH));
 
 
 	// Fog
 	// Fog
-	pass.newDependency(RenderPassDependency(m_r->getVolumetricFog().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+	pass.newDependency(RenderPassDependency(m_r->getVolumetricFog().getRt(), readUsage));
 
 
 	// For forward shading
 	// For forward shading
 	m_r->getForwardShading().setDependencies(ctx, pass);
 	m_r->getForwardShading().setDependencies(ctx, pass);

+ 8 - 0
AnKi/Renderer/LightShading.h

@@ -43,6 +43,13 @@ private:
 		Array<ShaderProgramPtr, 2> m_grProg;
 		Array<ShaderProgramPtr, 2> m_grProg;
 	} m_lightShading;
 	} m_lightShading;
 
 
+	class
+	{
+	public:
+		ShaderProgramResourcePtr m_prog;
+		ShaderProgramPtr m_grProg;
+	} m_applyIndirect;
+
 	class
 	class
 	{
 	{
 	public:
 	public:
@@ -58,6 +65,7 @@ private:
 
 
 	ANKI_USE_RESULT Error initLightShading(const ConfigSet& config);
 	ANKI_USE_RESULT Error initLightShading(const ConfigSet& config);
 	ANKI_USE_RESULT Error initApplyFog(const ConfigSet& config);
 	ANKI_USE_RESULT Error initApplyFog(const ConfigSet& config);
+	ANKI_USE_RESULT Error initApplyIndirect(const ConfigSet& config);
 
 
 	void run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
 	void run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
 };
 };

+ 2 - 7
AnKi/Renderer/MotionVectors.cpp

@@ -78,13 +78,8 @@ void MotionVectors::run(const RenderingContext& ctx, RenderPassWorkContext& rgra
 		Mat4 m_prevViewProjectionInvMat;
 		Mat4 m_prevViewProjectionInvMat;
 	} pc;
 	} pc;
 
 
-	// This reprojection is not enterely correct. It first unprojects the current depth to world space, all fine here.
-	// Then it projects it to the previous frame but assumes identity jitter. Then it jitters using current frame's
-	// jitter. The last multiplication I don't get but it works perfectly for sampling the TAA history buffer.
-	pc.m_reprojectionMat = ctx.m_matrices.m_jitter * ctx.m_prevMatrices.m_viewProjection
-						   * ctx.m_matrices.m_viewProjectionJitter.getInverse();
-
-	pc.m_prevViewProjectionInvMat = ctx.m_prevMatrices.m_viewProjectionJitter.getInverse();
+	pc.m_reprojectionMat = ctx.m_matrices.m_reprojection;
+	pc.m_prevViewProjectionInvMat = ctx.m_prevMatrices.m_invertedProjectionJitter;
 	cmdb->setPushConstants(&pc, sizeof(pc));
 	cmdb->setPushConstants(&pc, sizeof(pc));
 
 
 	dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x(), m_r->getInternalResolution().y());
 	dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x(), m_r->getInternalResolution().y());

+ 16 - 17
AnKi/Renderer/Renderer.cpp

@@ -20,7 +20,6 @@
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/ShadowMapping.h>
 #include <AnKi/Renderer/ShadowMapping.h>
 #include <AnKi/Renderer/FinalComposite.h>
 #include <AnKi/Renderer/FinalComposite.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Bloom.h>
 #include <AnKi/Renderer/Bloom.h>
 #include <AnKi/Renderer/Tonemapping.h>
 #include <AnKi/Renderer/Tonemapping.h>
 #include <AnKi/Renderer/ForwardShading.h>
 #include <AnKi/Renderer/ForwardShading.h>
@@ -32,9 +31,8 @@
 #include <AnKi/Renderer/TemporalAA.h>
 #include <AnKi/Renderer/TemporalAA.h>
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/Ssr.h>
-#include <AnKi/Renderer/Ssgi.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
-#include <AnKi/Renderer/GlobalIllumination.h>
+#include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/GenericCompute.h>
 #include <AnKi/Renderer/GenericCompute.h>
 #include <AnKi/Renderer/ShadowmapsResolve.h>
 #include <AnKi/Renderer/ShadowmapsResolve.h>
 #include <AnKi/Renderer/RtShadows.h>
 #include <AnKi/Renderer/RtShadows.h>
@@ -42,6 +40,7 @@
 #include <AnKi/Renderer/MotionVectors.h>
 #include <AnKi/Renderer/MotionVectors.h>
 #include <AnKi/Renderer/ClusterBinning.h>
 #include <AnKi/Renderer/ClusterBinning.h>
 #include <AnKi/Renderer/Scale.h>
 #include <AnKi/Renderer/Scale.h>
+#include <AnKi/Renderer/IndirectDiffuse.h>
 
 
 namespace anki
 namespace anki
 {
 {
@@ -116,7 +115,7 @@ Error Renderer::initInternal(const ConfigSet& config)
 	}
 	}
 
 
 	{
 	{
-		TextureInitInfo texinit;
+		TextureInitInfo texinit("RendererDummy");
 		texinit.m_width = texinit.m_height = 4;
 		texinit.m_width = texinit.m_height = 4;
 		texinit.m_usage = TextureUsageBit::ALL_SAMPLED;
 		texinit.m_usage = TextureUsageBit::ALL_SAMPLED;
 		texinit.m_format = Format::R8G8B8A8_UNORM;
 		texinit.m_format = Format::R8G8B8A8_UNORM;
@@ -145,8 +144,8 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_volumetricLightingAccumulation.reset(m_alloc.newInstance<VolumetricLightingAccumulation>(this));
 	m_volumetricLightingAccumulation.reset(m_alloc.newInstance<VolumetricLightingAccumulation>(this));
 	ANKI_CHECK(m_volumetricLightingAccumulation->init(config));
 	ANKI_CHECK(m_volumetricLightingAccumulation->init(config));
 
 
-	m_globalIllumination.reset(m_alloc.newInstance<GlobalIllumination>(this));
-	ANKI_CHECK(m_globalIllumination->init(config));
+	m_indirectDiffuseProbes.reset(m_alloc.newInstance<IndirectDiffuseProbes>(this));
+	ANKI_CHECK(m_indirectDiffuseProbes->init(config));
 
 
 	m_probeReflections.reset(m_alloc.newInstance<ProbeReflections>(this));
 	m_probeReflections.reset(m_alloc.newInstance<ProbeReflections>(this));
 	ANKI_CHECK(m_probeReflections->init(config));
 	ANKI_CHECK(m_probeReflections->init(config));
@@ -175,18 +174,12 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_lensFlare.reset(m_alloc.newInstance<LensFlare>(this));
 	m_lensFlare.reset(m_alloc.newInstance<LensFlare>(this));
 	ANKI_CHECK(m_lensFlare->init(config));
 	ANKI_CHECK(m_lensFlare->init(config));
 
 
-	m_ssao.reset(m_alloc.newInstance<Ssao>(this));
-	ANKI_CHECK(m_ssao->init(config));
-
 	m_downscaleBlur.reset(getAllocator().newInstance<DownscaleBlur>(this));
 	m_downscaleBlur.reset(getAllocator().newInstance<DownscaleBlur>(this));
 	ANKI_CHECK(m_downscaleBlur->init(config));
 	ANKI_CHECK(m_downscaleBlur->init(config));
 
 
 	m_ssr.reset(m_alloc.newInstance<Ssr>(this));
 	m_ssr.reset(m_alloc.newInstance<Ssr>(this));
 	ANKI_CHECK(m_ssr->init(config));
 	ANKI_CHECK(m_ssr->init(config));
 
 
-	m_ssgi.reset(m_alloc.newInstance<Ssgi>(this));
-	ANKI_CHECK(m_ssgi->init(config));
-
 	m_tonemapping.reset(getAllocator().newInstance<Tonemapping>(this));
 	m_tonemapping.reset(getAllocator().newInstance<Tonemapping>(this));
 	ANKI_CHECK(m_tonemapping->init(config));
 	ANKI_CHECK(m_tonemapping->init(config));
 
 
@@ -208,6 +201,9 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_scale.reset(m_alloc.newInstance<Scale>(this));
 	m_scale.reset(m_alloc.newInstance<Scale>(this));
 	ANKI_CHECK(m_scale->init(config));
 	ANKI_CHECK(m_scale->init(config));
 
 
+	m_indirectDiffuse.reset(m_alloc.newInstance<IndirectDiffuse>(this));
+	ANKI_CHECK(m_indirectDiffuse->init(config));
+
 	if(getGrManager().getDeviceCapabilities().m_rayTracingEnabled && config.getBool("scene_rayTracedShadows"))
 	if(getGrManager().getDeviceCapabilities().m_rayTracingEnabled && config.getBool("scene_rayTracedShadows"))
 	{
 	{
 		m_accelerationStructureBuilder.reset(m_alloc.newInstance<AccelerationStructureBuilder>(this));
 		m_accelerationStructureBuilder.reset(m_alloc.newInstance<AccelerationStructureBuilder>(this));
@@ -297,10 +293,13 @@ void Renderer::initJitteredMats()
 
 
 Error Renderer::populateRenderGraph(RenderingContext& ctx)
 Error Renderer::populateRenderGraph(RenderingContext& ctx)
 {
 {
+	ctx.m_prevMatrices = m_prevMatrices;
+
 	ctx.m_matrices.m_cameraTransform = ctx.m_renderQueue->m_cameraTransform;
 	ctx.m_matrices.m_cameraTransform = ctx.m_renderQueue->m_cameraTransform;
 	ctx.m_matrices.m_view = ctx.m_renderQueue->m_viewMatrix;
 	ctx.m_matrices.m_view = ctx.m_renderQueue->m_viewMatrix;
 	ctx.m_matrices.m_projection = ctx.m_renderQueue->m_projectionMatrix;
 	ctx.m_matrices.m_projection = ctx.m_renderQueue->m_projectionMatrix;
 	ctx.m_matrices.m_viewProjection = ctx.m_renderQueue->m_viewProjectionMatrix;
 	ctx.m_matrices.m_viewProjection = ctx.m_renderQueue->m_viewProjectionMatrix;
+	ctx.m_matrices.m_viewRotation = ctx.m_renderQueue->m_viewMatrix.getRotationPart();
 
 
 	ctx.m_matrices.m_jitter = m_jitteredMats8x[m_frameCount & (m_jitteredMats8x.getSize() - 1)];
 	ctx.m_matrices.m_jitter = m_jitteredMats8x[m_frameCount & (m_jitteredMats8x.getSize() - 1)];
 	ctx.m_matrices.m_projectionJitter = ctx.m_matrices.m_jitter * ctx.m_matrices.m_projection;
 	ctx.m_matrices.m_projectionJitter = ctx.m_matrices.m_jitter * ctx.m_matrices.m_projection;
@@ -310,9 +309,10 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 	ctx.m_matrices.m_invertedProjectionJitter = ctx.m_matrices.m_projectionJitter.getInverse();
 	ctx.m_matrices.m_invertedProjectionJitter = ctx.m_matrices.m_projectionJitter.getInverse();
 	ctx.m_matrices.m_invertedView = ctx.m_matrices.m_view.getInverse();
 	ctx.m_matrices.m_invertedView = ctx.m_matrices.m_view.getInverse();
 
 
-	ctx.m_matrices.m_unprojectionParameters = ctx.m_matrices.m_projection.extractPerspectiveUnprojectionParams();
+	ctx.m_matrices.m_reprojection =
+		ctx.m_matrices.m_jitter * ctx.m_prevMatrices.m_viewProjection * ctx.m_matrices.m_invertedViewProjectionJitter;
 
 
-	ctx.m_prevMatrices = m_prevMatrices;
+	ctx.m_matrices.m_unprojectionParameters = ctx.m_matrices.m_projection.extractPerspectiveUnprojectionParams();
 
 
 	// Check if resources got loaded
 	// Check if resources got loaded
 	if(m_prevLoadRequestCount != m_resources->getLoadingRequestCount()
 	if(m_prevLoadRequestCount != m_resources->getLoadingRequestCount()
@@ -340,7 +340,7 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 		m_accelerationStructureBuilder->populateRenderGraph(ctx);
 		m_accelerationStructureBuilder->populateRenderGraph(ctx);
 	}
 	}
 	m_shadowMapping->populateRenderGraph(ctx);
 	m_shadowMapping->populateRenderGraph(ctx);
-	m_globalIllumination->populateRenderGraph(ctx);
+	m_indirectDiffuseProbes->populateRenderGraph(ctx);
 	m_probeReflections->populateRenderGraph(ctx);
 	m_probeReflections->populateRenderGraph(ctx);
 	m_volumetricLightingAccumulation->populateRenderGraph(ctx);
 	m_volumetricLightingAccumulation->populateRenderGraph(ctx);
 	m_gbuffer->populateRenderGraph(ctx);
 	m_gbuffer->populateRenderGraph(ctx);
@@ -356,10 +356,9 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 		m_shadowmapsResolve->populateRenderGraph(ctx);
 		m_shadowmapsResolve->populateRenderGraph(ctx);
 	}
 	}
 	m_volumetricFog->populateRenderGraph(ctx);
 	m_volumetricFog->populateRenderGraph(ctx);
-	m_ssao->populateRenderGraph(ctx);
 	m_lensFlare->populateRenderGraph(ctx);
 	m_lensFlare->populateRenderGraph(ctx);
 	m_ssr->populateRenderGraph(ctx);
 	m_ssr->populateRenderGraph(ctx);
-	m_ssgi->populateRenderGraph(ctx);
+	m_indirectDiffuse->populateRenderGraph(ctx);
 	m_lightShading->populateRenderGraph(ctx);
 	m_lightShading->populateRenderGraph(ctx);
 	m_temporalAA->populateRenderGraph(ctx);
 	m_temporalAA->populateRenderGraph(ctx);
 	m_scale->populateRenderGraph(ctx);
 	m_scale->populateRenderGraph(ctx);

+ 2 - 3
AnKi/Renderer/RendererObjectDefs.h

@@ -9,7 +9,6 @@ ANKI_RENDERER_OBJECT_DEF(ShadowMapping, shadowMapping)
 ANKI_RENDERER_OBJECT_DEF(LightShading, lightShading)
 ANKI_RENDERER_OBJECT_DEF(LightShading, lightShading)
 ANKI_RENDERER_OBJECT_DEF(ForwardShading, forwardShading)
 ANKI_RENDERER_OBJECT_DEF(ForwardShading, forwardShading)
 ANKI_RENDERER_OBJECT_DEF(LensFlare, lensFlare)
 ANKI_RENDERER_OBJECT_DEF(LensFlare, lensFlare)
-ANKI_RENDERER_OBJECT_DEF(Ssao, ssao)
 ANKI_RENDERER_OBJECT_DEF(Tonemapping, tonemapping)
 ANKI_RENDERER_OBJECT_DEF(Tonemapping, tonemapping)
 ANKI_RENDERER_OBJECT_DEF(Bloom, bloom)
 ANKI_RENDERER_OBJECT_DEF(Bloom, bloom)
 ANKI_RENDERER_OBJECT_DEF(FinalComposite, finalComposite)
 ANKI_RENDERER_OBJECT_DEF(FinalComposite, finalComposite)
@@ -21,9 +20,8 @@ ANKI_RENDERER_OBJECT_DEF(DepthDownscale, depthDownscale)
 ANKI_RENDERER_OBJECT_DEF(TemporalAA, temporalAA)
 ANKI_RENDERER_OBJECT_DEF(TemporalAA, temporalAA)
 ANKI_RENDERER_OBJECT_DEF(UiStage, uiStage)
 ANKI_RENDERER_OBJECT_DEF(UiStage, uiStage)
 ANKI_RENDERER_OBJECT_DEF(Ssr, ssr)
 ANKI_RENDERER_OBJECT_DEF(Ssr, ssr)
-ANKI_RENDERER_OBJECT_DEF(Ssgi, ssgi)
 ANKI_RENDERER_OBJECT_DEF(VolumetricLightingAccumulation, volumetricLightingAccumulation)
 ANKI_RENDERER_OBJECT_DEF(VolumetricLightingAccumulation, volumetricLightingAccumulation)
-ANKI_RENDERER_OBJECT_DEF(GlobalIllumination, globalIllumination)
+ANKI_RENDERER_OBJECT_DEF(IndirectDiffuseProbes, indirectDiffuseProbes)
 ANKI_RENDERER_OBJECT_DEF(GenericCompute, genericCompute)
 ANKI_RENDERER_OBJECT_DEF(GenericCompute, genericCompute)
 ANKI_RENDERER_OBJECT_DEF(ShadowmapsResolve, shadowmapsResolve)
 ANKI_RENDERER_OBJECT_DEF(ShadowmapsResolve, shadowmapsResolve)
 ANKI_RENDERER_OBJECT_DEF(RtShadows, rtShadows)
 ANKI_RENDERER_OBJECT_DEF(RtShadows, rtShadows)
@@ -31,3 +29,4 @@ ANKI_RENDERER_OBJECT_DEF(AccelerationStructureBuilder, accelerationStructureBuil
 ANKI_RENDERER_OBJECT_DEF(MotionVectors, motionVectors)
 ANKI_RENDERER_OBJECT_DEF(MotionVectors, motionVectors)
 ANKI_RENDERER_OBJECT_DEF(ClusterBinning, clusterBinning)
 ANKI_RENDERER_OBJECT_DEF(ClusterBinning, clusterBinning)
 ANKI_RENDERER_OBJECT_DEF(Scale, scale)
 ANKI_RENDERER_OBJECT_DEF(Scale, scale)
+ANKI_RENDERER_OBJECT_DEF(IndirectDiffuse, indirectDiffuse)

+ 0 - 259
AnKi/Renderer/Ssao.cpp

@@ -1,259 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Renderer/Ssao.h>
-#include <AnKi/Renderer/Renderer.h>
-#include <AnKi/Renderer/GBuffer.h>
-#include <AnKi/Renderer/RenderQueue.h>
-#include <AnKi/Renderer/DepthDownscale.h>
-#include <AnKi/Util/Functions.h>
-#include <AnKi/Core/ConfigSet.h>
-
-namespace anki
-{
-
-Ssao::~Ssao()
-{
-}
-
-Error Ssao::initMain(const ConfigSet& config)
-{
-	// Noise
-	ANKI_CHECK(getResourceManager().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_main.m_noiseImage));
-
-	// Shader
-	if(m_useCompute)
-	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/SsaoCompute.ankiprog", m_main.m_prog));
-	}
-	else
-	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/Ssao.ankiprog", m_main.m_prog));
-	}
-
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_main.m_prog);
-	variantInitInfo.addMutation("USE_NORMAL", (m_useNormal) ? 1u : 0u);
-	variantInitInfo.addMutation("SOFT_BLUR", (m_useSoftBlur) ? 1u : 0u);
-	variantInitInfo.addConstant("NOISE_MAP_SIZE", U32(m_main.m_noiseImage->getWidth()));
-	variantInitInfo.addConstant("FB_SIZE", UVec2(m_width, m_height));
-	variantInitInfo.addConstant("RADIUS", 2.5f);
-	variantInitInfo.addConstant("BIAS", 0.0f);
-	variantInitInfo.addConstant("STRENGTH", 2.5f);
-	variantInitInfo.addConstant("SAMPLE_COUNT", 8u);
-	const ShaderProgramResourceVariant* variant;
-	m_main.m_prog->getOrCreateVariant(variantInitInfo, variant);
-	m_main.m_workgroupSize[0] = variant->getWorkgroupSizes()[0];
-	m_main.m_workgroupSize[1] = variant->getWorkgroupSizes()[1];
-	m_main.m_grProg = variant->getProgram();
-
-	return Error::NONE;
-}
-
-Error Ssao::initBlur(const ConfigSet& config)
-{
-	// shader
-	if(m_blurUseCompute)
-	{
-		ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/GaussianBlurCompute.ankiprog", m_blur.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_blur.m_prog);
-		variantInitInfo.addMutation("ORIENTATION", 2);
-		variantInitInfo.addMutation("KERNEL_SIZE", 3);
-		variantInitInfo.addMutation("COLOR_COMPONENTS", 1);
-		variantInitInfo.addConstant("TEXTURE_SIZE", UVec2(m_width, m_height));
-
-		const ShaderProgramResourceVariant* variant;
-		m_blur.m_prog->getOrCreateVariant(variantInitInfo, variant);
-
-		m_blur.m_workgroupSize[0] = variant->getWorkgroupSizes()[0];
-		m_blur.m_workgroupSize[1] = variant->getWorkgroupSizes()[1];
-
-		m_blur.m_grProg = variant->getProgram();
-	}
-	else
-	{
-		ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/GaussianBlur.ankiprog", m_blur.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_blur.m_prog);
-		variantInitInfo.addMutation("ORIENTATION", 2);
-		variantInitInfo.addMutation("KERNEL_SIZE", 3);
-		variantInitInfo.addMutation("COLOR_COMPONENTS", 1);
-		variantInitInfo.addConstant("TEXTURE_SIZE", UVec2(m_width, m_height));
-
-		const ShaderProgramResourceVariant* variant;
-		m_blur.m_prog->getOrCreateVariant(variantInitInfo, variant);
-
-		m_blur.m_grProg = variant->getProgram();
-	}
-
-	return Error::NONE;
-}
-
-Error Ssao::init(const ConfigSet& config)
-{
-	m_width = m_r->getInternalResolution().x() / SSAO_FRACTION;
-	m_height = m_r->getInternalResolution().y() / SSAO_FRACTION;
-
-	ANKI_R_LOGI("Initializing SSAO. Size %ux%u", m_width, m_height);
-
-	// RT
-	m_rtDescrs[0] = m_r->create2DRenderTargetDescription(m_width, m_height, RT_PIXEL_FORMAT, "SSAOMain");
-	m_rtDescrs[0].bake();
-
-	m_rtDescrs[1] = m_r->create2DRenderTargetDescription(m_width, m_height, RT_PIXEL_FORMAT, "SSAOBlur");
-	m_rtDescrs[1].bake();
-
-	// FB descr
-	m_fbDescr.m_colorAttachmentCount = 1;
-	m_fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
-	m_fbDescr.bake();
-
-	Error err = initMain(config);
-
-	if(!err)
-	{
-		err = initBlur(config);
-	}
-
-	if(err)
-	{
-		ANKI_R_LOGE("Failed to init PPS SSAO");
-	}
-
-	return err;
-}
-
-void Ssao::runMain(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-
-	cmdb->bindShaderProgram(m_main.m_grProg);
-
-	// Bind resources
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	cmdb->bindSampler(0, 1, m_r->getSamplers().m_trilinearRepeat);
-
-	rgraphCtx.bindTexture(0, 2, m_r->getDepthDownscale().getHiZRt(), HIZ_HALF_DEPTH);
-	cmdb->bindTexture(0, 3, m_main.m_noiseImage->getTextureView());
-
-	if(m_useNormal)
-	{
-		rgraphCtx.bindColorTexture(0, 4, m_r->getGBuffer().getColorRt(2));
-	}
-
-	struct Unis
-	{
-		Vec4 m_unprojectionParams;
-		Vec4 m_projectionMat;
-		Mat3x4 m_viewRotMat;
-	} unis;
-
-	const Mat4& pmat = ctx.m_renderQueue->m_projectionMatrix;
-	unis.m_unprojectionParams = ctx.m_matrices.m_unprojectionParameters;
-	unis.m_projectionMat = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
-	unis.m_viewRotMat = Mat3x4(Vec3(0.0f), ctx.m_renderQueue->m_viewMatrix.getRotationPart());
-	cmdb->setPushConstants(&unis, sizeof(unis));
-
-	if(m_useCompute)
-	{
-		rgraphCtx.bindImage(0, 5, m_runCtx.m_rts[0], TextureSubresourceInfo());
-		dispatchPPCompute(cmdb, m_main.m_workgroupSize[0], m_main.m_workgroupSize[1], m_width, m_height);
-	}
-	else
-	{
-		cmdb->setViewport(0, 0, m_width, m_height);
-		drawQuad(cmdb);
-	}
-}
-
-void Ssao::runBlur(RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-
-	cmdb->bindShaderProgram(m_blur.m_grProg);
-
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_rts[0]);
-
-	if(m_blurUseCompute)
-	{
-		rgraphCtx.bindImage(0, 2, m_runCtx.m_rts[1], TextureSubresourceInfo());
-		dispatchPPCompute(cmdb, m_blur.m_workgroupSize[0], m_blur.m_workgroupSize[1], m_width, m_height);
-	}
-	else
-	{
-		cmdb->setViewport(0, 0, m_width, m_height);
-		drawQuad(cmdb);
-	}
-}
-
-void Ssao::populateRenderGraph(RenderingContext& ctx)
-{
-	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
-
-	// Create RTs
-	m_runCtx.m_rts[0] = rgraph.newRenderTarget(m_rtDescrs[0]);
-	m_runCtx.m_rts[1] = rgraph.newRenderTarget(m_rtDescrs[1]);
-
-	// Create main render pass
-	{
-		if(m_useCompute)
-		{
-			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("SSAO main");
-
-			if(m_useNormal)
-			{
-				pass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
-			}
-
-			pass.newDependency({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_COMPUTE, HIZ_HALF_DEPTH});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-
-			pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) { runMain(ctx, rgraphCtx); });
-		}
-		else
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO main");
-
-			pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[0]}}, {});
-
-			if(m_useNormal)
-			{
-				pass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_FRAGMENT});
-			}
-
-			pass.newDependency(
-				{m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_FRAGMENT, HIZ_HALF_DEPTH});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-
-			pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) { runMain(ctx, rgraphCtx); });
-		}
-	}
-
-	// Create Blur pass
-	{
-		if(m_blurUseCompute)
-		{
-			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("SSAO blur");
-
-			pass.setWork([this](RenderPassWorkContext& rgraphCtx) { runBlur(rgraphCtx); });
-
-			pass.newDependency({m_runCtx.m_rts[1], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_COMPUTE});
-		}
-		else
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO blur");
-
-			pass.setWork([this](RenderPassWorkContext& rgraphCtx) { runBlur(rgraphCtx); });
-			pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[1]}}, {});
-
-			pass.newDependency({m_runCtx.m_rts[1], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_FRAGMENT});
-		}
-	}
-}
-
-} // end namespace anki

+ 0 - 90
AnKi/Renderer/Ssao.h

@@ -1,90 +0,0 @@
-// 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/Renderer/RendererObject.h>
-#include <AnKi/Resource/ImageResource.h>
-#include <AnKi/Gr.h>
-
-namespace anki
-{
-
-/// @addtogroup renderer
-/// @{
-
-/// Screen space ambient occlusion pass
-class Ssao : public RendererObject
-{
-public:
-	static const Format RT_PIXEL_FORMAT = Format::R8_UNORM;
-
-	Ssao(Renderer* r)
-		: RendererObject(r)
-	{
-		registerDebugRenderTarget("SsaoFinal");
-	}
-
-	~Ssao();
-
-	ANKI_USE_RESULT Error init(const ConfigSet& config);
-
-	/// Populate the rendergraph.
-	void populateRenderGraph(RenderingContext& ctx);
-
-	RenderTargetHandle getRt() const
-	{
-		return m_runCtx.m_rts[1];
-	}
-
-	void getDebugRenderTarget(CString rtName, RenderTargetHandle& handle,
-							  ShaderProgramPtr& optionalShaderProgram) const override
-	{
-		ANKI_ASSERT(rtName == "SsaoFinal");
-		handle = getRt();
-	}
-
-private:
-	static const Bool m_useNormal = false;
-	static const Bool m_useCompute = true;
-	static const Bool m_useSoftBlur = true;
-	static const Bool m_blurUseCompute = true;
-	U32 m_width, m_height;
-
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		ShaderProgramPtr m_grProg;
-		ImageResourcePtr m_noiseImage;
-		Array<U32, 2> m_workgroupSize = {};
-	} m_main; ///< Main noisy pass.
-
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		ShaderProgramPtr m_grProg;
-		Array<U32, 2> m_workgroupSize = {};
-	} m_blur; ///< Box blur.
-
-	class
-	{
-	public:
-		Array<RenderTargetHandle, 2> m_rts;
-	} m_runCtx; ///< Runtime context.
-
-	Array<RenderTargetDescription, 2> m_rtDescrs;
-	FramebufferDescription m_fbDescr;
-
-	ANKI_USE_RESULT Error initMain(const ConfigSet& set);
-	ANKI_USE_RESULT Error initBlur(const ConfigSet& set);
-
-	void runMain(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
-	void runBlur(RenderPassWorkContext& rgraphCtx);
-};
-/// @}
-
-} // end namespace anki

+ 0 - 277
AnKi/Renderer/Ssgi.cpp

@@ -1,277 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Renderer/Ssgi.h>
-#include <AnKi/Renderer/Renderer.h>
-#include <AnKi/Renderer/DepthDownscale.h>
-#include <AnKi/Renderer/GBuffer.h>
-#include <AnKi/Renderer/DownscaleBlur.h>
-#include <AnKi/Renderer/MotionVectors.h>
-#include <AnKi/Core/ConfigSet.h>
-#include <AnKi/Shaders/Include/SsgiTypes.h>
-
-namespace anki
-{
-
-static constexpr U32 WRITE = 0;
-static constexpr U32 READ = 1;
-
-Ssgi::~Ssgi()
-{
-}
-
-Error Ssgi::init(const ConfigSet& cfg)
-{
-	const Error err = initInternal(cfg);
-	if(err)
-	{
-		ANKI_R_LOGE("Failed to initialize SSGI pass");
-	}
-	return err;
-}
-
-Error Ssgi::initInternal(const ConfigSet& cfg)
-{
-	const U32 width = m_r->getInternalResolution().x();
-	const U32 height = m_r->getInternalResolution().y();
-	ANKI_ASSERT((width % 2) == 0 && (height % 2) == 0 && "The algorithms won't work");
-	ANKI_R_LOGI("Initializing SSGI pass");
-	m_main.m_maxSteps = cfg.getNumberU32("r_ssgiMaxSteps");
-	m_main.m_depthLod = min(cfg.getNumberU32("r_ssgiDepthLod"), m_r->getDepthDownscale().getMipmapCount() - 1);
-	m_main.m_firstStepPixels = 32;
-
-	ANKI_CHECK(getResourceManager().loadResource("EngineAssets/BlueNoise_Rgba8_16x16.png", m_main.m_noiseImage));
-
-	// Init main
-	{
-		m_main.m_rtDescr =
-			m_r->create2DRenderTargetDescription(width / 2, height / 2, Format::B10G11R11_UFLOAT_PACK32, "SSGI_tmp");
-		m_main.m_rtDescr.bake();
-
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/Ssgi.ankiprog", m_main.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_main.m_prog);
-
-		for(U32 i = 0; i < 4; ++i)
-		{
-			variantInitInfo.addMutation("VARIANT", i);
-
-			const ShaderProgramResourceVariant* variant;
-			m_main.m_prog->getOrCreateVariant(variantInitInfo, variant);
-			m_main.m_grProg[i] = variant->getProgram();
-		}
-	}
-
-	// Init denoise
-	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/SsgiDenoise.ankiprog", m_denoise.m_prog));
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_denoise.m_prog);
-		const ShaderProgramResourceVariant* variant;
-
-		variantInitInfo.addConstant("IN_TEXTURE_SIZE", UVec2(width / 2, height / 2));
-
-		for(U32 i = 0; i < 4; ++i)
-		{
-			variantInitInfo.addMutation("VARIANT", i);
-
-			variantInitInfo.addMutation("SAMPLE_COUNT", 11);
-			variantInitInfo.addMutation("ORIENTATION", 0);
-			m_denoise.m_prog->getOrCreateVariant(variantInitInfo, variant);
-			m_denoise.m_grProg[0][i] = variant->getProgram();
-
-			variantInitInfo.addMutation("SAMPLE_COUNT", 15);
-			variantInitInfo.addMutation("ORIENTATION", 1);
-			m_denoise.m_prog->getOrCreateVariant(variantInitInfo, variant);
-			m_denoise.m_grProg[1][i] = variant->getProgram();
-		}
-	}
-
-	// Init reconstruction
-	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/SsgiReconstruct.ankiprog", m_recontruction.m_prog));
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_recontruction.m_prog);
-		variantInitInfo.addConstant("FB_SIZE",
-									UVec2(m_r->getInternalResolution().x(), m_r->getInternalResolution().y()));
-		const ShaderProgramResourceVariant* variant;
-
-		for(U32 i = 0; i < 4; ++i)
-		{
-			variantInitInfo.addMutation("VARIANT", i);
-			m_recontruction.m_prog->getOrCreateVariant(variantInitInfo, variant);
-			m_recontruction.m_grProg[i] = variant->getProgram();
-		}
-
-		TextureInitInfo initInfo = m_r->create2DRenderTargetInitInfo(
-			width, height, Format::B10G11R11_UFLOAT_PACK32,
-			TextureUsageBit::ALL_SAMPLED | TextureUsageBit::IMAGE_COMPUTE_WRITE, "SSGI");
-		initInfo.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
-		m_recontruction.m_rt = m_r->createAndClearRenderTarget(initInfo);
-	}
-
-	return Error::NONE;
-}
-
-void Ssgi::populateRenderGraph(RenderingContext& ctx)
-{
-	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
-	m_runCtx.m_ctx = &ctx;
-
-	// Main pass
-	{
-		// Create RTs
-		if(ANKI_LIKELY(m_recontruction.m_rtImportedOnce))
-		{
-			m_runCtx.m_finalRt = rgraph.importRenderTarget(m_recontruction.m_rt);
-		}
-		else
-		{
-			m_runCtx.m_finalRt = rgraph.importRenderTarget(m_recontruction.m_rt, TextureUsageBit::SAMPLED_FRAGMENT);
-			m_recontruction.m_rtImportedOnce = true;
-		}
-		m_runCtx.m_intermediateRts[WRITE] = rgraph.newRenderTarget(m_main.m_rtDescr);
-		m_runCtx.m_intermediateRts[READ] = rgraph.newRenderTarget(m_main.m_rtDescr);
-
-		// Create pass
-		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("SSGI");
-		rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) { run(ctx, rgraphCtx); });
-
-		rpass.newDependency({m_runCtx.m_intermediateRts[WRITE], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-		rpass.newDependency({m_runCtx.m_finalRt, TextureUsageBit::SAMPLED_COMPUTE});
-
-		TextureSubresourceInfo hizSubresource;
-		hizSubresource.m_firstMipmap = m_main.m_depthLod;
-		rpass.newDependency({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_COMPUTE, hizSubresource});
-		rpass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_r->getDownscaleBlur().getRt(), TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_r->getMotionVectors().getMotionVectorsRt(), TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_r->getMotionVectors().getRejectionFactorRt(), TextureUsageBit::SAMPLED_COMPUTE});
-	}
-
-	// Blur vertical
-	{
-		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("SSGI_blur_v");
-
-		rpass.newDependency({m_runCtx.m_intermediateRts[WRITE], TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_runCtx.m_intermediateRts[READ], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-		rpass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_COMPUTE});
-
-		rpass.setWork([this](RenderPassWorkContext& rgraphCtx) { runVBlur(rgraphCtx); });
-	}
-
-	// Blur horizontal
-	{
-		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("SSGI_blur_h");
-
-		rpass.newDependency({m_runCtx.m_intermediateRts[READ], TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_runCtx.m_intermediateRts[WRITE], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-		rpass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_COMPUTE});
-
-		rpass.setWork([this](RenderPassWorkContext& rgraphCtx) { runHBlur(rgraphCtx); });
-	}
-
-	// Reconstruction
-	{
-		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("SSGI_recon");
-
-		rpass.newDependency({m_runCtx.m_intermediateRts[WRITE], TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_runCtx.m_finalRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
-		rpass.newDependency({m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_COMPUTE});
-		rpass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
-
-		rpass.setWork([this](RenderPassWorkContext& rgraphCtx) { runRecontruct(rgraphCtx); });
-	}
-}
-
-void Ssgi::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	cmdb->bindShaderProgram(m_main.m_grProg[m_r->getFrameCount() % 4]);
-
-	rgraphCtx.bindImage(0, 0, m_runCtx.m_intermediateRts[WRITE], TextureSubresourceInfo());
-
-	// Bind uniforms
-	SsgiUniforms* unis = allocateAndBindUniforms<SsgiUniforms*>(sizeof(SsgiUniforms), cmdb, 0, 1);
-	unis->m_depthBufferSize =
-		UVec2(m_r->getInternalResolution().x(), m_r->getInternalResolution().y()) >> (m_main.m_depthLod + 1);
-	unis->m_framebufferSize = UVec2(m_r->getInternalResolution().x(), m_r->getInternalResolution().y());
-	unis->m_invProjMat = ctx.m_matrices.m_projectionJitter.getInverse();
-	unis->m_projMat = ctx.m_matrices.m_projectionJitter;
-	unis->m_prevViewProjMatMulInvViewProjMat =
-		ctx.m_prevMatrices.m_viewProjection * ctx.m_matrices.m_viewProjectionJitter.getInverse();
-	unis->m_normalMat = Mat3x4(Vec3(0.0f), ctx.m_matrices.m_view.getRotationPart());
-	unis->m_frameCount = m_r->getFrameCount() & MAX_U32;
-	unis->m_maxSteps = m_main.m_maxSteps;
-	unis->m_firstStepPixels = m_main.m_firstStepPixels;
-
-	cmdb->bindSampler(0, 2, m_r->getSamplers().m_trilinearClamp);
-
-	rgraphCtx.bindColorTexture(0, 3, m_r->getGBuffer().getColorRt(2));
-
-	TextureSubresourceInfo hizSubresource;
-	hizSubresource.m_firstMipmap = m_main.m_depthLod;
-	rgraphCtx.bindTexture(0, 4, m_r->getDepthDownscale().getHiZRt(), hizSubresource);
-
-	rgraphCtx.bindColorTexture(0, 5, m_r->getDownscaleBlur().getRt());
-	rgraphCtx.bindColorTexture(0, 6, m_runCtx.m_finalRt);
-	rgraphCtx.bindColorTexture(0, 7, m_r->getMotionVectors().getMotionVectorsRt());
-	rgraphCtx.bindColorTexture(0, 8, m_r->getMotionVectors().getRejectionFactorRt());
-
-	// Dispatch
-	dispatchPPCompute(cmdb, 16, 16, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
-}
-
-void Ssgi::runVBlur(RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	cmdb->bindShaderProgram(m_denoise.m_grProg[0][m_r->getFrameCount() % 4]);
-
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_intermediateRts[WRITE]);
-	rgraphCtx.bindTexture(0, 2, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
-	rgraphCtx.bindColorTexture(0, 3, m_r->getGBuffer().getColorRt(2));
-
-	rgraphCtx.bindImage(0, 4, m_runCtx.m_intermediateRts[READ], TextureSubresourceInfo());
-
-	const Mat4 mat = m_runCtx.m_ctx->m_matrices.m_viewProjectionJitter.getInverse();
-	cmdb->setPushConstants(&mat, sizeof(mat));
-
-	dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
-}
-
-void Ssgi::runHBlur(RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	cmdb->bindShaderProgram(m_denoise.m_grProg[1][m_r->getFrameCount() % 4]);
-
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_intermediateRts[READ]);
-	rgraphCtx.bindTexture(0, 2, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
-	rgraphCtx.bindColorTexture(0, 3, m_r->getGBuffer().getColorRt(2));
-
-	rgraphCtx.bindImage(0, 4, m_runCtx.m_intermediateRts[WRITE], TextureSubresourceInfo());
-
-	const Mat4 mat = m_runCtx.m_ctx->m_matrices.m_viewProjectionJitter.getInverse();
-	cmdb->setPushConstants(&mat, sizeof(mat));
-
-	dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
-}
-
-void Ssgi::runRecontruct(RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	cmdb->bindShaderProgram(m_recontruction.m_grProg[m_r->getFrameCount() % 4]);
-
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_intermediateRts[WRITE]);
-	rgraphCtx.bindTexture(0, 2, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
-
-	rgraphCtx.bindImage(0, 3, m_runCtx.m_finalRt, TextureSubresourceInfo());
-
-	dispatchPPCompute(cmdb, 16, 16, m_r->getInternalResolution().x(), m_r->getInternalResolution().y());
-}
-
-} // end namespace anki

+ 0 - 93
AnKi/Renderer/Ssgi.h

@@ -1,93 +0,0 @@
-// 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/Renderer/RendererObject.h>
-#include <AnKi/Resource/ImageResource.h>
-#include <AnKi/Gr.h>
-
-namespace anki
-{
-
-/// @addtogroup renderer
-/// @{
-
-/// Screen space global illumination.
-class Ssgi : public RendererObject
-{
-public:
-	Ssgi(Renderer* r)
-		: RendererObject(r)
-	{
-		registerDebugRenderTarget("SSGI");
-	}
-
-	~Ssgi();
-
-	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
-
-	/// Populate the rendergraph.
-	void populateRenderGraph(RenderingContext& ctx);
-
-	RenderTargetHandle getRt() const
-	{
-		return m_runCtx.m_finalRt;
-	}
-
-	void getDebugRenderTarget(CString rtName, RenderTargetHandle& handle,
-							  ShaderProgramPtr& optionalShaderProgram) const override
-	{
-		ANKI_ASSERT(rtName == "SSGI");
-		handle = m_runCtx.m_finalRt;
-	}
-
-private:
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		Array<ShaderProgramPtr, 4> m_grProg;
-		RenderTargetDescription m_rtDescr;
-		ImageResourcePtr m_noiseImage;
-		U32 m_maxSteps = 32;
-		U32 m_firstStepPixels = 16;
-		U32 m_depthLod = 0;
-	} m_main;
-
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		Array2d<ShaderProgramPtr, 2, 4> m_grProg;
-	} m_denoise;
-
-	class
-	{
-	public:
-		TexturePtr m_rt;
-		ShaderProgramResourcePtr m_prog;
-		Array<ShaderProgramPtr, 4> m_grProg;
-		Bool m_rtImportedOnce = false;
-	} m_recontruction;
-
-	class
-	{
-	public:
-		Array<RenderTargetHandle, 2> m_intermediateRts;
-		RenderTargetHandle m_finalRt;
-		RenderingContext* m_ctx = nullptr;
-	} m_runCtx;
-
-	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
-
-	void run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
-	void runVBlur(RenderPassWorkContext& rgraphCtx);
-	void runHBlur(RenderPassWorkContext& rgraphCtx);
-	void runRecontruct(RenderPassWorkContext& rgraphCtx);
-};
-/// @}
-
-} // namespace anki

+ 3 - 3
AnKi/Renderer/VolumetricLightingAccumulation.cpp

@@ -5,7 +5,7 @@
 
 
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
 #include <AnKi/Renderer/ShadowMapping.h>
 #include <AnKi/Renderer/ShadowMapping.h>
-#include <AnKi/Renderer/GlobalIllumination.h>
+#include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Resource/ImageResource.h>
 #include <AnKi/Resource/ImageResource.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Core/ConfigSet.h>
@@ -95,7 +95,7 @@ void VolumetricLightingAccumulation::populateRenderGraph(RenderingContext& ctx)
 	pass.newDependency(
 	pass.newDependency(
 		RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_COMPUTE_READ));
 		RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_COMPUTE_READ));
 
 
-	m_r->getGlobalIllumination().setRenderGraphDependencies(ctx, pass, TextureUsageBit::SAMPLED_COMPUTE);
+	m_r->getIndirectDiffuseProbes().setRenderGraphDependencies(ctx, pass, TextureUsageBit::SAMPLED_COMPUTE);
 }
 }
 
 
 void VolumetricLightingAccumulation::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
 void VolumetricLightingAccumulation::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
@@ -120,7 +120,7 @@ void VolumetricLightingAccumulation::run(const RenderingContext& ctx, RenderPass
 	bindUniforms(cmdb, 0, 7, rsrc.m_spotLightsToken);
 	bindUniforms(cmdb, 0, 7, rsrc.m_spotLightsToken);
 	rgraphCtx.bindColorTexture(0, 8, m_r->getShadowMapping().getShadowmapRt());
 	rgraphCtx.bindColorTexture(0, 8, m_r->getShadowMapping().getShadowmapRt());
 
 
-	m_r->getGlobalIllumination().bindVolumeTextures(ctx, rgraphCtx, 0, 9);
+	m_r->getIndirectDiffuseProbes().bindVolumeTextures(ctx, rgraphCtx, 0, 9);
 	bindUniforms(cmdb, 0, 10, rsrc.m_globalIlluminationProbesToken);
 	bindUniforms(cmdb, 0, 10, rsrc.m_globalIlluminationProbesToken);
 
 
 	bindUniforms(cmdb, 0, 11, rsrc.m_fogDensityVolumesToken);
 	bindUniforms(cmdb, 0, 11, rsrc.m_fogDensityVolumesToken);

+ 1 - 0
AnKi/ShaderCompiler/ShaderProgramParser.cpp

@@ -173,6 +173,7 @@ static const char* SHADER_HEADER = R"(#version 460 core
 #endif
 #endif
 
 
 #define Mat3 mat3
 #define Mat3 mat3
+#define _ANKI_SIZEOF_mat3 36u
 
 
 #define Mat4 mat4
 #define Mat4 mat4
 #define _ANKI_SIZEOF_mat4 64u
 #define _ANKI_SIZEOF_mat4 64u

+ 1 - 1
AnKi/Shaders/ImportanceSampling.glsl

@@ -74,4 +74,4 @@ U32 hashPcg(U32 u)
 	const U32 state = u * 747796405u + 2891336453u;
 	const U32 state = u * 747796405u + 2891336453u;
 	const U32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
 	const U32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
 	return (word >> 22u) ^ word;
 	return (word >> 22u) ^ word;
-}
+}

+ 18 - 2
AnKi/Shaders/Include/ClusteredShadingTypes.h

@@ -163,6 +163,9 @@ struct CommonMatrices
 	Mat4 m_view ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_view ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_projection ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_projection ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_viewProjection ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_viewProjection ANKI_CPP_CODE(= Mat4::getIdentity());
+	Mat3 m_viewRotation ANKI_CPP_CODE(= Mat3::getIdentity());
+
+	F32 m_padding[3u]; // Because of the alignment requirements of some of the following members (in C++)
 
 
 	Mat4 m_jitter ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_jitter ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_projectionJitter ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_projectionJitter ANKI_CPP_CODE(= Mat4::getIdentity());
@@ -173,9 +176,22 @@ struct CommonMatrices
 	Mat4 m_invertedProjectionJitter ANKI_CPP_CODE(= Mat4::getIdentity()); ///< To unproject in view space.
 	Mat4 m_invertedProjectionJitter ANKI_CPP_CODE(= Mat4::getIdentity()); ///< To unproject in view space.
 	Mat4 m_invertedView ANKI_CPP_CODE(= Mat4::getIdentity());
 	Mat4 m_invertedView ANKI_CPP_CODE(= Mat4::getIdentity());
 
 
-	Vec4 m_unprojectionParameters ANKI_CPP_CODE(= Vec4(0.0f)); ///< To unproject to view space. Jitter not considered.
+	/// It's being used to reproject a clip space position of the current frame to the previous frame. Its value should
+	/// be m_jitter * m_prevFrame.m_viewProjection * m_invertedViewProjectionJitter. At first it unprojects the current
+	/// position to world space, all fine here. Then it projects to the previous frame as if the previous frame was
+	/// using the current frame's jitter matrix.
+	Mat4 m_reprojection ANKI_CPP_CODE(= Mat4::getIdentity());
+
+	/// To unproject to view space. Jitter not considered.
+	/// @code
+	/// const F32 z = m_unprojectionParameters.z / (m_unprojectionParameters.w + depth);
+	/// const Vec2 xy = ndc * m_unprojectionParameters.xy * z;
+	/// pos = Vec3(xy, z);
+	/// @endcode
+	Vec4 m_unprojectionParameters ANKI_CPP_CODE(= Vec4(0.0f));
 };
 };
-const U32 _ANKI_SIZEOF_CommonMatrices = 11u * ANKI_SIZEOF(Mat4) + ANKI_SIZEOF(Vec4);
+const U32 _ANKI_SIZEOF_CommonMatrices =
+	12u * ANKI_SIZEOF(Mat4) + ANKI_SIZEOF(Vec4) + ANKI_SIZEOF(Mat3) + ANKI_SIZEOF(F32) * 3u;
 ANKI_SHADER_STATIC_ASSERT(sizeof(CommonMatrices) == _ANKI_SIZEOF_CommonMatrices);
 ANKI_SHADER_STATIC_ASSERT(sizeof(CommonMatrices) == _ANKI_SIZEOF_CommonMatrices);
 
 
 /// Common uniforms for light shading passes.
 /// Common uniforms for light shading passes.

+ 34 - 0
AnKi/Shaders/Include/IndirectDiffuseTypes.h

@@ -0,0 +1,34 @@
+// 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
+
+struct IndirectDiffuseUniforms
+{
+	UVec2 m_viewportSize;
+	Vec2 m_viewportSizef;
+	Vec4 m_projectionMat;
+	F32 m_radius; ///< In meters.
+	U32 m_sampleCount;
+	F32 m_sampleCountf;
+	F32 m_ssaoBias;
+	F32 m_ssaoStrength;
+	F32 m_padding[3u];
+};
+
+struct IndirectDiffuseDenoiseUniforms
+{
+	Mat4 m_invertedViewProjectionJitterMat;
+	UVec2 m_viewportSize;
+	Vec2 m_viewportSizef;
+	F32 m_sampleCountDiv2;
+	F32 m_padding[3u];
+};
+
+ANKI_END_NAMESPACE

+ 216 - 0
AnKi/Shaders/IndirectDiffuse.ankiprog

@@ -0,0 +1,216 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// Does SSGI and GI probe sampling
+
+ANKI_SPECIALIZATION_CONSTANT_U32(SAMPLE_COUNT, 6u);
+
+#define ENABLE_SSGI true
+#define ENABLE_PROBES true
+#define REMOVE_FIREFLIES false
+#define REPROJECT_LIGHTBUFFER false
+#define SSGI_PROBE_COMBINE(ssgiColor, probeColor) ((ssgiColor) + (probeColor))
+
+#pragma anki start comp
+#include <AnKi/Shaders/Functions.glsl>
+#include <AnKi/Shaders/PackFunctions.glsl>
+#include <AnKi/Shaders/ImportanceSampling.glsl>
+#include <AnKi/Shaders/TonemappingFunctions.glsl>
+#include <AnKi/Shaders/Include/IndirectDiffuseTypes.h>
+
+const UVec2 WORKGROUP_SIZE = UVec2(8, 8);
+layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y) in;
+
+#define CLUSTERED_SHADING_SET 0
+#define CLUSTERED_SHADING_UNIFORMS_BINDING 0
+#define CLUSTERED_SHADING_GI_BINDING 1
+#define CLUSTERED_SHADING_CLUSTERS_BINDING 3
+#include <AnKi/Shaders/ClusteredShadingCommon.glsl>
+
+layout(set = 0, binding = 4) writeonly uniform image2D u_outImage;
+
+layout(set = 0, binding = 5) uniform sampler u_linearAnyClampSampler;
+layout(set = 0, binding = 6) uniform texture2D u_gbufferRt2;
+layout(set = 0, binding = 7) uniform texture2D u_depthRt;
+layout(set = 0, binding = 8) uniform texture2D u_lightBufferRt;
+layout(set = 0, binding = 9) uniform texture2D u_historyTex;
+layout(set = 0, binding = 10) uniform texture2D u_motionVectorsTex;
+layout(set = 0, binding = 11) uniform texture2D u_motionVectorsRejectionTex;
+
+layout(push_constant, std430) uniform b_pc
+{
+	IndirectDiffuseUniforms u_unis;
+};
+
+Vec4 cheapProject(Vec4 point)
+{
+	return projectPerspective(point, u_unis.m_projectionMat.x, u_unis.m_projectionMat.y, u_unis.m_projectionMat.z,
+							  u_unis.m_projectionMat.w);
+}
+
+void main()
+{
+	const UVec2 fixedGlobalInvocationId = min(gl_GlobalInvocationID.xy, u_unis.m_viewportSize);
+	const Vec2 fragCoord = Vec2(fixedGlobalInvocationId.xy) + 0.5;
+	const Vec2 uv = fragCoord / u_unis.m_viewportSizef;
+	const Vec2 ndc = UV_TO_NDC(uv);
+
+	// Get normal
+	const Vec3 worldNormal = readNormalFromGBuffer(u_gbufferRt2, u_linearAnyClampSampler, uv);
+	const Vec3 viewNormal = u_clusteredShading.m_matrices.m_viewRotation * worldNormal;
+
+	// Get origin
+	const F32 depth = textureLod(u_depthRt, u_linearAnyClampSampler, uv, 0.0).r;
+	Vec4 v4 = u_clusteredShading.m_matrices.m_invertedViewProjectionJitter * Vec4(ndc, depth, 1.0);
+	const Vec3 worldPos = v4.xyz / v4.w;
+	v4 = u_clusteredShading.m_matrices.m_invertedProjectionJitter * Vec4(ndc, depth, 1.0);
+	const Vec3 viewPos = v4.xyz / v4.w;
+
+	// SSGI
+	Vec3 outColor = Vec3(0.0);
+	F32 ssao = 0.0;
+	if(ENABLE_SSGI)
+	{
+		// Find the projected radius
+		const Vec3 sphereLimit = viewPos + Vec3(u_unis.m_radius, 0.0, 0.0);
+		const Vec4 projSphereLimit = cheapProject(Vec4(sphereLimit, 1.0));
+		const Vec2 projSphereLimit2 = projSphereLimit.xy / projSphereLimit.w;
+		const F32 projRadius = length(projSphereLimit2 - ndc);
+
+		// Loop to compute
+		const UVec2 random = rand3DPCG16(UVec3(gl_GlobalInvocationID.xy, u_clusteredShading.m_frame)).xy;
+		for(U32 i = 0u; i < u_unis.m_sampleCount; ++i)
+		{
+			const Vec2 point = UV_TO_NDC(hammersleyRandom16(i, u_unis.m_sampleCount, random));
+			const Vec2 finalDiskPoint = ndc + point * projRadius;
+
+			// Do a cheap unproject in view space
+			const F32 d = textureLod(u_depthRt, u_linearAnyClampSampler, NDC_TO_UV(finalDiskPoint), 0.0).r;
+			const F32 z = u_clusteredShading.m_matrices.m_unprojectionParameters.z
+						  / (u_clusteredShading.m_matrices.m_unprojectionParameters.w + d);
+			const Vec2 xy = finalDiskPoint * u_clusteredShading.m_matrices.m_unprojectionParameters.xy * z;
+			const Vec3 s = Vec3(xy, z);
+
+			// Compute factor
+			const Vec3 dir = s - viewPos;
+			const F32 len = length(dir);
+			const Vec3 n = dir / len;
+			const F32 NoL = max(0.0, dot(viewNormal, n));
+			// const F32 distFactor = 1.0 - sin(min(1.0, len / u_unis.m_radius) * PI / 2.0);
+			const F32 distFactor = 1.0 - min(1.0, len / u_unis.m_radius);
+
+			// Compute the UV for sampling the pyramid
+			const Vec2 crntFrameUv = NDC_TO_UV(finalDiskPoint);
+			Vec2 lastFrameUv;
+			if(REPROJECT_LIGHTBUFFER)
+			{
+				lastFrameUv =
+					crntFrameUv + textureLod(u_motionVectorsTex, u_linearAnyClampSampler, crntFrameUv, 0.0).xy;
+			}
+			else
+			{
+				lastFrameUv = crntFrameUv;
+			}
+
+			// Append color
+			const F32 w = distFactor * NoL;
+			const Vec3 c = textureLod(u_lightBufferRt, u_linearAnyClampSampler, lastFrameUv, 100.0).xyz;
+			outColor += c * w;
+
+			// Compute SSAO as well
+			ssao += max(dot(viewNormal, dir) + u_unis.m_ssaoBias, EPSILON) / max(len * len, EPSILON);
+		}
+
+		const F32 scount = 1.0 / u_unis.m_sampleCountf;
+		outColor *= scount * 2.0 * PI;
+		ssao *= scount;
+	}
+
+	ssao = min(1.0, 1.0 - ssao * u_unis.m_ssaoStrength);
+
+	if(ENABLE_PROBES)
+	{
+		// Sample probes
+
+		Vec3 probeColor = Vec3(0.0);
+
+		// Get the cluster
+		Cluster cluster = getClusterFragCoord(Vec3(fragCoord * 2.0, depth));
+
+		// Get world position
+		const Vec4 worldPos4 = u_clusteredShading.m_matrices.m_invertedViewProjectionJitter * Vec4(ndc, depth, 1.0);
+		const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
+
+		if(bitCount(cluster.m_giProbesMask) == 1)
+		{
+			// All subgroups point to the same probe and there is only one probe, do a fast path without blend weight
+
+			const GlobalIlluminationProbe probe = u_giProbes[findLSB2(cluster.m_giProbesMask)];
+
+			// Sample
+			probeColor = sampleGlobalIllumination(worldPos, worldNormal, probe, u_globalIlluminationTextures,
+												  u_linearAnyClampSampler);
+		}
+		else
+		{
+			// Zero or more than one probes, do a slow path that blends them together
+
+			F32 totalBlendWeight = EPSILON;
+
+			// Loop probes
+			ANKI_LOOP while(cluster.m_giProbesMask != 0u)
+			{
+				const U32 idx = U32(findLSB2(cluster.m_giProbesMask));
+				cluster.m_giProbesMask &= ~(1u << idx);
+				const GlobalIlluminationProbe probe = u_giProbes[idx];
+
+				// Compute blend weight
+				const F32 blendWeight =
+					computeProbeBlendWeight(worldPos, probe.m_aabbMin, probe.m_aabbMax, probe.m_fadeDistance);
+				totalBlendWeight += blendWeight;
+
+				// Sample
+				const Vec3 c = sampleGlobalIllumination(worldPos, worldNormal, probe, u_globalIlluminationTextures,
+														u_linearAnyClampSampler);
+				probeColor += c * blendWeight;
+			}
+
+			// Normalize
+			probeColor /= totalBlendWeight;
+		}
+
+		outColor = SSGI_PROBE_COMBINE(outColor, probeColor);
+	}
+
+	// Remove fireflies
+	if(REMOVE_FIREFLIES)
+	{
+		const F32 lum = computeLuminance(outColor) + 0.001;
+		const F32 averageLum = (subgroupAdd(lum) / F32(gl_SubgroupSize)) * 2.0;
+		const F32 newLum = min(lum, averageLum);
+		outColor *= newLum / lum;
+	}
+
+	// Apply SSAO
+	outColor *= ssao;
+
+	// Blend color with history
+	{
+		const Vec2 historyUv = uv + textureLod(u_motionVectorsTex, u_linearAnyClampSampler, uv, 0.0).xy;
+		const F32 historyRejectionFactor = textureLod(u_motionVectorsRejectionTex, u_linearAnyClampSampler, uv, 0.0).x;
+
+		const F32 lowestBlendFactor = 0.1;
+		const F32 blendFactor = mix(lowestBlendFactor, 1.0, historyRejectionFactor);
+
+		// Blend with history
+		const Vec3 history = textureLod(u_historyTex, u_linearAnyClampSampler, historyUv, 0.0).rgb;
+		outColor = mix(history, outColor, blendFactor);
+	}
+
+	// Store color
+	imageStore(u_outImage, IVec2(fixedGlobalInvocationId), Vec4(outColor, 1.0));
+}
+
+#pragma anki end

+ 88 - 0
AnKi/Shaders/IndirectDiffuseDenoise.ankiprog

@@ -0,0 +1,88 @@
+// 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 mutator BLUR_ORIENTATION 0 1 // 0: in X asix, 1: in Y axis
+
+#pragma anki start comp
+
+#include <AnKi/Shaders/Include/IndirectDiffuseTypes.h>
+#include <AnKi/Shaders/PackFunctions.glsl>
+#include <AnKi/Shaders/Functions.glsl>
+#include <AnKi/Shaders/BilateralFilter.glsl>
+
+const UVec2 WORKGROUP_SIZE = UVec2(8u, 8u);
+layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y) in;
+
+layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
+layout(set = 0, binding = 1) uniform texture2D u_toDenoiseTex;
+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;
+
+layout(push_constant, std430, row_major) uniform b_pc
+{
+	IndirectDiffuseDenoiseUniforms u_unis;
+};
+
+Vec3 unproject(Vec2 ndc, F32 depth)
+{
+	const Vec4 worldPos4 = u_unis.m_invertedViewProjectionJitterMat * Vec4(ndc, depth, 1.0);
+	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
+	return worldPos;
+}
+
+void main()
+{
+	if(skipOutOfBoundsInvocations(WORKGROUP_SIZE, u_unis.m_viewportSize))
+	{
+		return;
+	}
+
+	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / u_unis.m_viewportSizef;
+
+	// Reference
+	const F32 depthCenter = textureLod(u_depthTex, u_linearAnyClampSampler, uv, 0.0).r;
+	if(depthCenter == 1.0)
+	{
+		imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(0.0));
+		return;
+	}
+
+	const Vec3 positionCenter = unproject(UV_TO_NDC(uv), depthCenter);
+	const Vec3 normalCenter = readNormalFromGBuffer(u_gbuffer2Tex, u_linearAnyClampSampler, uv);
+
+	// Sample
+	F32 weight = EPSILON;
+	Vec3 color = Vec3(0.0);
+
+	for(F32 i = -u_unis.m_sampleCountDiv2; i <= u_unis.m_sampleCountDiv2; i += 1.0)
+	{
+		const Vec2 texelSize = 1.0 / u_unis.m_viewportSizef;
+#if BLUR_ORIENTATION == 0
+		const Vec2 sampleUv = Vec2(uv.x + i * texelSize.x, uv.y);
+#else
+		const Vec2 sampleUv = Vec2(uv.x, uv.y + i * texelSize.y);
+#endif
+
+		const F32 depthTap = textureLod(u_depthTex, u_linearAnyClampSampler, sampleUv, 0.0).r;
+		const Vec3 positionTap = unproject(UV_TO_NDC(sampleUv), depthTap);
+		const Vec3 normalTap =
+			unpackNormalFromGBuffer(textureLod(u_gbuffer2Tex, u_linearAnyClampSampler, sampleUv, 0.0));
+
+		F32 w = calculateBilateralWeightPlane(positionCenter, normalCenter, positionTap, normalTap, 1.0);
+		// w *= gaussianWeight(0.4, abs(F32(i)) / (sampleCount + 1.0));
+		weight += w;
+
+		color += textureLod(u_toDenoiseTex, u_linearAnyClampSampler, sampleUv, 0.0).xyz * w;
+	}
+
+	// Normalize and store
+	color /= weight;
+	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(color, 0.0));
+	// imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), textureLod(u_toDenoiseTex, u_linearAnyClampSampler, uv,
+	// 0.0));
+}
+
+#pragma anki end

+ 1 - 1
AnKi/Shaders/IrradianceDice.ankiprog

@@ -194,7 +194,7 @@ void main()
 #	else
 #	else
 		Vec3 irradiance = s_diceIrradiance[f];
 		Vec3 irradiance = s_diceIrradiance[f];
 #	endif
 #	endif
-		const Vec3 toStoreValue = irradiance;
+		const Vec3 toStoreValue = irradiance * PI;
 #elif DEBUG_MODE == 1
 #elif DEBUG_MODE == 1
 		const Vec3 toStoreValue = colorPerCubeFace(f);
 		const Vec3 toStoreValue = colorPerCubeFace(f);
 #else
 #else

+ 10 - 65
AnKi/Shaders/LightShading.ankiprog

@@ -23,24 +23,21 @@ ANKI_SPECIALIZATION_CONSTANT_U32(IR_MIPMAP_COUNT, 4u);
 #define CLUSTERED_SHADING_UNIFORMS_BINDING 0
 #define CLUSTERED_SHADING_UNIFORMS_BINDING 0
 #define CLUSTERED_SHADING_LIGHTS_BINDING 1
 #define CLUSTERED_SHADING_LIGHTS_BINDING 1
 #define CLUSTERED_SHADING_REFLECTIONS_BINDING 4
 #define CLUSTERED_SHADING_REFLECTIONS_BINDING 4
-#define CLUSTERED_SHADING_GI_BINDING 7
-#define CLUSTERED_SHADING_CLUSTERS_BINDING 9
+#define CLUSTERED_SHADING_CLUSTERS_BINDING 7
 #include <AnKi/Shaders/ClusteredShadingCommon.glsl>
 #include <AnKi/Shaders/ClusteredShadingCommon.glsl>
 
 
-layout(set = 0, binding = 10) uniform sampler u_nearestAnyClampSampler;
-layout(set = 0, binding = 11) uniform sampler u_trilinearClampSampler;
+layout(set = 0, binding = 8) uniform sampler u_nearestAnyClampSampler;
+layout(set = 0, binding = 9) uniform sampler u_trilinearClampSampler;
 
 
-layout(set = 0, binding = 12) uniform texture2D u_msRt0;
-layout(set = 0, binding = 13) uniform texture2D u_msRt1;
-layout(set = 0, binding = 14) uniform texture2D u_msRt2;
-layout(set = 0, binding = 15) uniform texture2D u_msDepthRt;
-layout(set = 0, binding = 16) uniform texture2D u_ssrRt;
-layout(set = 0, binding = 17) uniform texture2D u_ssaoRt;
-layout(set = 0, binding = 18) uniform texture2D u_ssgiRt;
+layout(set = 0, binding = 10) uniform texture2D u_msRt0;
+layout(set = 0, binding = 11) uniform texture2D u_msRt1;
+layout(set = 0, binding = 12) uniform texture2D u_msRt2;
+layout(set = 0, binding = 13) uniform texture2D u_msDepthRt;
+layout(set = 0, binding = 14) uniform texture2D u_ssrRt;
 #if USE_SHADOW_LAYERS
 #if USE_SHADOW_LAYERS
-layout(set = 0, binding = 19) uniform utexture2D u_shadowLayersTex;
+layout(set = 0, binding = 15) uniform utexture2D u_shadowLayersTex;
 #else
 #else
-layout(set = 0, binding = 20) uniform texture2D u_resolvedSm;
+layout(set = 0, binding = 16) uniform texture2D u_resolvedSm;
 #endif
 #endif
 
 
 layout(location = 0) in Vec2 in_uv;
 layout(location = 0) in Vec2 in_uv;
@@ -91,10 +88,6 @@ void main()
 	U32 resolvedSmIdx = 0u;
 	U32 resolvedSmIdx = 0u;
 #endif
 #endif
 
 
-	// SSAO
-	const F32 ssao = textureLod(u_ssaoRt, u_trilinearClampSampler, in_uv, 0.0).r;
-	gbuffer.m_diffuse *= ssao;
-
 	// Ambient and emissive color
 	// Ambient and emissive color
 	out_color = gbuffer.m_diffuse * gbuffer.m_emission;
 	out_color = gbuffer.m_diffuse * gbuffer.m_emission;
 
 
@@ -235,53 +228,5 @@ void main()
 
 
 		out_color += finalSpecIndirect * env;
 		out_color += finalSpecIndirect * env;
 	}
 	}
-
-	// Indirect diffuse
-	{
-		Vec3 diffIndirect;
-
-		if(bitCount(cluster.m_giProbesMask) == 1)
-		{
-			// All subgroups point to the same probe and there is only one probe, do a fast path without blend weight
-
-			const GlobalIlluminationProbe probe = u_giProbes[findLSB2(cluster.m_giProbesMask)];
-
-			// Sample
-			diffIndirect = sampleGlobalIllumination(worldPos, gbuffer.m_normal, probe, u_globalIlluminationTextures,
-													u_trilinearClampSampler);
-		}
-		else
-		{
-			// Zero or more than one probes, do a slow path that blends them together
-
-			F32 totalBlendWeight = EPSILON;
-			diffIndirect = Vec3(0.0);
-
-			// Loop probes
-			ANKI_LOOP while(cluster.m_giProbesMask != 0u)
-			{
-				const U32 idx = U32(findLSB2(cluster.m_giProbesMask));
-				cluster.m_giProbesMask &= ~(1u << idx);
-				const GlobalIlluminationProbe probe = u_giProbes[idx];
-
-				// Compute blend weight
-				const F32 blendWeight =
-					computeProbeBlendWeight(worldPos, probe.m_aabbMin, probe.m_aabbMax, probe.m_fadeDistance);
-				totalBlendWeight += blendWeight;
-
-				// Sample
-				const Vec3 c = sampleGlobalIllumination(worldPos, gbuffer.m_normal, probe, u_globalIlluminationTextures,
-														u_trilinearClampSampler);
-				diffIndirect += c * blendWeight;
-			}
-
-			// Normalize
-			diffIndirect /= totalBlendWeight;
-		}
-
-		const Vec3 ssgi = textureLod(u_ssgiRt, u_trilinearClampSampler, in_uv, 0.0).rgb;
-		diffIndirect += ssgi;
-		out_color += diffIndirect * gbuffer.m_diffuse;
-	}
 }
 }
 #pragma anki end
 #pragma anki end

+ 58 - 0
AnKi/Shaders/LightShadingApplyIndirect.ankiprog

@@ -0,0 +1,58 @@
+// 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 vert
+#include <AnKi/Shaders/QuadVert.glsl>
+#pragma anki end
+
+#pragma anki start frag
+#include <AnKi/Shaders/BilateralFilter.glsl>
+
+layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
+layout(set = 0, binding = 1) uniform sampler u_linearAnyClampSampler;
+layout(set = 0, binding = 2) uniform texture2D u_quarterDiffuseIndirectTex;
+layout(set = 0, binding = 3) uniform texture2D u_quarterDepthTex;
+layout(set = 0, binding = 4) uniform texture2D u_fullDepthTex;
+layout(set = 0, binding = 5) uniform texture2D u_gbuffer0Tex;
+
+layout(push_constant, std430) uniform b_pc
+{
+	Vec2 u_quadTexelSize;
+	Vec2 u_padding;
+};
+
+layout(location = 0) in Vec2 in_uv;
+layout(location = 0) out Vec3 out_color;
+
+void main()
+{
+	// Reference
+	const F32 depthCenter = textureLod(u_fullDepthTex, u_linearAnyClampSampler, in_uv, 0.0).x;
+
+	// Do a bilateral upscale
+	out_color = Vec3(0.0);
+	const F32 radius = 1.0;
+	F32 sumWeight = EPSILON;
+	for(F32 x = -radius; x <= radius; x += 1.0)
+	{
+		for(F32 y = -radius; y <= radius; y += 1.0)
+		{
+			const Vec2 sampleUv = in_uv + Vec2(x, y) * u_quadTexelSize;
+			const F32 depthTap = textureLod(u_quarterDepthTex, u_linearAnyClampSampler, sampleUv, 0.0).x;
+
+			const F32 w = calculateBilateralWeightDepth(depthCenter, depthTap, 1.0);
+			sumWeight += w;
+
+			const Vec3 colorTap = textureLod(u_quarterDiffuseIndirectTex, u_nearestAnyClampSampler, sampleUv, 0.0).xyz;
+			out_color += colorTap * w;
+		}
+	}
+
+	// Modulate
+	out_color /= sumWeight;
+	const Vec3 albedo = textureLod(u_gbuffer0Tex, u_linearAnyClampSampler, in_uv, 0.0).xyz;
+	out_color *= albedo;
+}
+#pragma anki end

+ 20 - 11
AnKi/Shaders/SsRaymarching.glsl

@@ -147,8 +147,15 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 						 Vec2 uv, // UV the ray starts
 						 Vec2 uv, // UV the ray starts
 						 F32 depthRef, // Depth the ray starts
 						 F32 depthRef, // Depth the ray starts
 						 Mat4 projMat, // Projection matrix
 						 Mat4 projMat, // Projection matrix
-						 U32 maxIterations, texture2D depthTex, sampler depthSampler, F32 depthLod, UVec2 depthTexSize,
-						 U32 bigStep, U32 randInitialStep, out Vec3 hitPoint, out F32 attenuation)
+						 U32 maxSteps, // The max iterations of the base algorithm
+						 texture2D depthTex, // Depth tex
+						 sampler depthSampler, // Sampler for depthTex
+						 F32 depthLod, // LOD to pass to the textureLod
+						 UVec2 depthTexSize, // Size of the depthTex
+						 U32 initialStepIncrement, // Initial step increment
+						 U32 randInitialStep, // The initial step
+						 out Vec3 hitPoint, // Hit point in UV coordinates
+						 out F32 attenuation)
 {
 {
 	attenuation = 0.0;
 	attenuation = 0.0;
 
 
@@ -177,14 +184,14 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 	dir = normalize(dir);
 	dir = normalize(dir);
 
 
 	// Compute step
 	// Compute step
-	I32 stepSkip = I32(bigStep);
-	I32 step = I32(randInitialStep);
+	I32 stepIncrement = I32(initialStepIncrement);
+	I32 crntStep = I32(randInitialStep);
 
 
-	// Iterate
+	// Search
 	Vec3 origin;
 	Vec3 origin;
-	ANKI_LOOP while(maxIterations-- != 0u)
+	ANKI_LOOP while(maxSteps-- != 0u)
 	{
 	{
-		origin = start + dir * (F32(step) * stepSize);
+		origin = start + dir * (F32(crntStep) * stepSize);
 
 
 		// Check if it's out of the view
 		// Check if it's out of the view
 		if(origin.x <= 0.0 || origin.y <= 0.0 || origin.x >= 1.0 || origin.y >= 1.0)
 		if(origin.x <= 0.0 || origin.y <= 0.0 || origin.x >= 1.0 || origin.y >= 1.0)
@@ -196,12 +203,14 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 		const Bool hit = origin.z - depth >= 0.0;
 		const Bool hit = origin.z - depth >= 0.0;
 		if(!hit)
 		if(!hit)
 		{
 		{
-			step += stepSkip;
+			crntStep += stepIncrement;
 		}
 		}
-		else if(stepSkip > 1)
+		else if(stepIncrement > 1)
 		{
 		{
-			step = max(1, step - stepSkip + 1);
-			stepSkip = stepSkip / 2;
+			// There is a hit but the step increment is a bit high, need a more fine-grained search
+
+			crntStep = max(1, crntStep - stepIncrement + 1);
+			stepIncrement = stepIncrement / 2;
 		}
 		}
 		else
 		else
 		{
 		{

+ 0 - 12
AnKi/Shaders/Ssao.ankiprog

@@ -1,12 +0,0 @@
-// 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 vert
-#include <AnKi/Shaders/QuadVert.glsl>
-#pragma anki end
-
-#pragma anki start frag
-#include <AnKi/Shaders/Ssao.glsl>
-#pragma anki end

+ 0 - 226
AnKi/Shaders/Ssao.glsl

@@ -1,226 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-// Contains the complete code for a SSAO pass. It requires some variables to be defined before this file is included.
-
-#pragma anki mutator USE_NORMAL 0 1
-#pragma anki mutator SOFT_BLUR 0 1
-
-ANKI_SPECIALIZATION_CONSTANT_U32(NOISE_MAP_SIZE, 0u);
-ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 1u);
-ANKI_SPECIALIZATION_CONSTANT_F32(RADIUS, 3u);
-ANKI_SPECIALIZATION_CONSTANT_F32(BIAS, 4u);
-ANKI_SPECIALIZATION_CONSTANT_F32(STRENGTH, 5u);
-ANKI_SPECIALIZATION_CONSTANT_U32(SAMPLE_COUNT, 6u);
-
-#pragma once
-
-#include <AnKi/Shaders/Common.glsl>
-#include <AnKi/Shaders/PackFunctions.glsl>
-#include <AnKi/Shaders/Functions.glsl>
-#define KERNEL_SIZE 3
-#include <AnKi/Shaders/GaussianBlurCommon.glsl>
-
-#if defined(ANKI_FRAGMENT_SHADER)
-#	define USE_COMPUTE 0
-#else
-#	define USE_COMPUTE 1
-const UVec2 WORKGROUP_SIZE = UVec2(16, 16);
-#endif
-
-// Do a compute soft blur
-#define DO_SOFT_BLUR (USE_COMPUTE && SOFT_BLUR)
-
-#if !USE_COMPUTE
-layout(location = 0) in Vec2 in_uv;
-layout(location = 0) out F32 out_color;
-#else
-layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 5) writeonly uniform image2D out_img;
-#endif
-
-layout(push_constant, std140, row_major) uniform b_pc
-{
-	Vec4 u_unprojectionParams;
-	Vec4 u_projectionMat;
-	Mat3 u_viewRotMat;
-};
-
-layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
-layout(set = 0, binding = 1) uniform sampler u_trilinearRepeatSampler;
-
-layout(set = 0, binding = 2) uniform texture2D u_depthRt;
-layout(set = 0, binding = 3) uniform texture2D u_noiseMap;
-#if USE_NORMAL
-layout(set = 0, binding = 4) uniform texture2D u_msRt;
-#endif
-
-// To compute the normals we need some extra work on compute
-#define COMPLEX_NORMALS (!USE_NORMAL && USE_COMPUTE)
-#if DO_SOFT_BLUR
-shared Vec3 s_scratch[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
-#endif
-
-#if USE_NORMAL
-// Get normal
-Vec3 readNormal(Vec2 uv)
-{
-	Vec3 normal = readNormalFromGBuffer(u_msRt, u_linearAnyClampSampler, uv);
-	normal = u_viewRotMat * normal;
-	return normal;
-}
-#endif
-
-// Read the noise tex
-Vec3 readRandom(Vec2 uv, F32 layer)
-{
-	const Vec2 tmp = Vec2(F32(FB_SIZE.x) / F32(NOISE_MAP_SIZE), F32(FB_SIZE.y) / F32(NOISE_MAP_SIZE));
-	const Vec3 r = textureLod(u_noiseMap, u_trilinearRepeatSampler, tmp * uv, 0.0).rgb;
-	return r;
-}
-
-Vec4 project(Vec4 point)
-{
-	return projectPerspective(point, u_projectionMat.x, u_projectionMat.y, u_projectionMat.z, u_projectionMat.w);
-}
-
-Vec3 unproject(Vec2 ndc, F32 depth)
-{
-	const F32 z = u_unprojectionParams.z / (u_unprojectionParams.w + depth);
-	const Vec2 xy = ndc * u_unprojectionParams.xy * z;
-	return Vec3(xy, z);
-}
-
-F32 smallerDelta(F32 left, F32 mid, F32 right)
-{
-	const F32 a = mid - left;
-	const F32 b = right - mid;
-
-	return (abs(a) < abs(b)) ? a : b;
-}
-
-// Compute the normal depending on some defines
-Vec3 computeNormal(Vec2 uv, Vec3 origin, F32 depth)
-{
-#if USE_NORMAL
-	const Vec3 normal = readNormal(uv);
-#elif !COMPLEX_NORMALS
-	const Vec3 normal = normalize(cross(dFdx(origin), dFdy(origin)));
-#else
-	const F32 depthLeft = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(-2, 0)).r;
-	const F32 depthRight = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(2, 0)).r;
-	const F32 depthTop = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(0, 2)).r;
-	const F32 depthBottom = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(0, -2)).r;
-
-	const F32 ddx = smallerDelta(depthLeft, depth, depthRight);
-	const F32 ddy = smallerDelta(depthBottom, depth, depthTop);
-
-	const Vec2 ndc = UV_TO_NDC(uv);
-	const Vec2 TEXEL_SIZE = 1.0 / Vec2(FB_SIZE);
-	const Vec2 NDC_TEXEL_SIZE = 2.0 * TEXEL_SIZE;
-	const Vec3 right = unproject(ndc + Vec2(NDC_TEXEL_SIZE.x, 0.0), depth + ddx);
-	const Vec3 top = unproject(ndc + Vec2(0.0, NDC_TEXEL_SIZE.y), depth + ddy);
-
-	Vec3 normal = cross(origin - top, right - origin);
-	normal = normalize(normal);
-#endif
-
-	return normal;
-}
-
-void main(void)
-{
-#if USE_COMPUTE
-	const UVec2 globalInvocationID = min(gl_GlobalInvocationID.xy, FB_SIZE - 1u);
-	const Vec2 uv = (Vec2(globalInvocationID) + 0.5) / Vec2(FB_SIZE);
-#else
-	const Vec2 uv = in_uv;
-#endif
-
-	const Vec2 ndc = UV_TO_NDC(uv);
-
-	// Compute origin
-	const F32 depth = textureLod(u_depthRt, u_linearAnyClampSampler, uv, 0.0).r;
-	const Vec3 origin = unproject(ndc, depth);
-
-	// Get normal
-	const Vec3 normal = computeNormal(uv, origin, depth);
-
-	// Find the projected radius
-	const Vec3 sphereLimit = origin + Vec3(RADIUS, 0.0, 0.0);
-	const Vec4 projSphereLimit = project(Vec4(sphereLimit, 1.0));
-	const Vec2 projSphereLimit2 = projSphereLimit.xy / projSphereLimit.w;
-	const F32 projRadius = length(projSphereLimit2 - ndc);
-
-	// Loop to compute
-	const F32 randFactor = readRandom(uv, 0.0).r;
-	F32 ssao = 0.0;
-	const F32 SAMPLE_COUNTF = F32(SAMPLE_COUNT);
-	ANKI_UNROLL for(U32 i = 0u; i < SAMPLE_COUNT; ++i)
-	{
-		// Compute disk. Basically calculate a point in a spiral. See how it looks here
-		// https://shadertoy.com/view/Md3fDr
-		const F32 fi = F32(i);
-		const F32 TURNS = F32(SAMPLE_COUNT) / 2.0; // Calculate the number of the spiral turns
-		const F32 ANG = (PI * 2.0 * TURNS) / (SAMPLE_COUNTF - 1.0); // The angle distance between samples
-		F32 ang = ANG * fi;
-		ang += randFactor * PI; // Turn the angle a bit
-
-		F32 radius = (1.0 / SAMPLE_COUNTF) * (fi + 1.0);
-		radius = sqrt(radius); // Move the points a bit away from the center of the spiral
-
-		const Vec2 point = Vec2(cos(ang), sin(ang)) * radius; // In NDC
-
-		const Vec2 finalDiskPoint = ndc + point * projRadius;
-
-		// Compute factor
-		const Vec3 s =
-			unproject(finalDiskPoint, textureLod(u_depthRt, u_linearAnyClampSampler, NDC_TO_UV(finalDiskPoint), 0.0).r);
-		const Vec3 u = s - origin;
-		ssao += max(dot(normal, u) + BIAS, EPSILON) / max(dot(u, u), EPSILON);
-	}
-
-	ssao *= (1.0 / F32(SAMPLE_COUNT));
-	ssao = 1.0 - ssao * STRENGTH;
-
-	// Maybe do soft blur
-#if DO_SOFT_BLUR
-	// Everyone stores its result
-	s_scratch[gl_LocalInvocationID.y][gl_LocalInvocationID.x].x = ssao;
-
-	// Do some pre-work to find out the neighbours
-	const U32 left = (gl_LocalInvocationID.x != 0u) ? (gl_LocalInvocationID.x - 1u) : 0u;
-	const U32 right =
-		(gl_LocalInvocationID.x != WORKGROUP_SIZE.x - 1u) ? (gl_LocalInvocationID.x + 1u) : (WORKGROUP_SIZE.x - 1u);
-	const U32 bottom = (gl_LocalInvocationID.y != 0u) ? (gl_LocalInvocationID.y - 1u) : 0u;
-	const U32 top =
-		(gl_LocalInvocationID.y != WORKGROUP_SIZE.y - 1u) ? (gl_LocalInvocationID.y + 1u) : (WORKGROUP_SIZE.y - 1u);
-
-	// Wait for all threads
-	memoryBarrierShared();
-	barrier();
-
-	// Sample neighbours
-	ssao += s_scratch[gl_LocalInvocationID.y][left].x;
-	ssao += s_scratch[gl_LocalInvocationID.y][right].x;
-	ssao += s_scratch[bottom][gl_LocalInvocationID.x].x;
-	ssao += s_scratch[top][gl_LocalInvocationID.x].x;
-
-	ssao += s_scratch[bottom][left].x;
-	ssao += s_scratch[bottom][right].x;
-	ssao += s_scratch[top][left].x;
-	ssao += s_scratch[top][right].x;
-
-	ssao *= (1.0 / 9.0);
-#endif
-
-	// Store the result
-#if USE_COMPUTE
-	imageStore(out_img, IVec2(globalInvocationID), Vec4(ssao));
-#else
-	out_color = ssao;
-#endif
-}

+ 0 - 8
AnKi/Shaders/SsaoCompute.ankiprog

@@ -1,8 +0,0 @@
-// 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
-#include <AnKi/Shaders/Ssao.glsl>
-#pragma anki end

+ 0 - 156
AnKi/Shaders/Ssgi.ankiprog

@@ -1,156 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-// The VARIANT points to the fragment in the quad that will be processed:
-// -----
-// |3|2|
-// |0|1|
-// -----
-
-#pragma anki mutator VARIANT 0 1 2 3
-
-#pragma anki start comp
-#include <AnKi/Shaders/SsRaymarching.glsl>
-#include <AnKi/Shaders/Functions.glsl>
-#include <AnKi/Shaders/PackFunctions.glsl>
-#include <AnKi/Shaders/ImportanceSampling.glsl>
-#include <AnKi/Shaders/Include/SsgiTypes.h>
-
-const UVec2 WORKGROUP_SIZE = UVec2(16, 16);
-layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 0, rgba16f) uniform image2D out_img;
-
-layout(set = 0, binding = 1, row_major, std140) uniform u_
-{
-	SsgiUniforms u_unis;
-};
-
-layout(set = 0, binding = 2) uniform sampler u_trilinearClampSampler;
-layout(set = 0, binding = 3) uniform texture2D u_gbufferRt2;
-layout(set = 0, binding = 4) uniform texture2D u_depthRt;
-layout(set = 0, binding = 5) uniform texture2D u_lightBufferRt;
-layout(set = 0, binding = 6) uniform texture2D u_historyTex;
-layout(set = 0, binding = 7) uniform texture2D u_motionVectorsTex;
-layout(set = 0, binding = 8) uniform texture2D u_motionVectorRejectionTex;
-
-void main()
-{
-	// Compute a global invocation ID that takes the checkerboard pattern into account
-	UVec2 fixedGlobalInvocationId = gl_GlobalInvocationID.xy;
-	fixedGlobalInvocationId *= 2u;
-#if VARIANT == 0
-	// Nothing
-#elif VARIANT == 1
-	fixedGlobalInvocationId.x += 1u;
-#elif VARIANT == 2
-	fixedGlobalInvocationId += 1u;
-#else
-	fixedGlobalInvocationId.y += 1u;
-#endif
-
-	if(fixedGlobalInvocationId.x >= u_unis.m_framebufferSize.x
-	   || fixedGlobalInvocationId.y >= u_unis.m_framebufferSize.y)
-	{
-		// Skip threads outside the writable image
-		return;
-	}
-
-	const Vec2 uv = (Vec2(fixedGlobalInvocationId.xy) + 0.5) / Vec2(u_unis.m_framebufferSize);
-	const Vec2 ndc = UV_TO_NDC(uv);
-
-	// Get normal
-	const Vec3 worldNormal = readNormalFromGBuffer(u_gbufferRt2, u_trilinearClampSampler, uv);
-	const Vec3 viewNormal = u_unis.m_normalMat * worldNormal;
-
-	// Get depth
-	const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, uv, 0.0).r;
-
-	// Compute view pos
-	const Vec4 viewPos4 = u_unis.m_invProjMat * Vec4(ndc, depth, 1.0);
-	const Vec3 viewPos = viewPos4.xyz / viewPos4.w;
-
-	// Get a random point inside the hemisphere. Use hemisphereSampleCos to avoid perpendicular vecs to viewNormal
-	const UVec2 random = rand3DPCG16(UVec3(gl_GlobalInvocationID.xy, u_unis.m_frameCount)).xy;
-	Vec2 randomCircle = hammersleyRandom16(0u, 0xFFFFu, random);
-	randomCircle.x *= 0.85; // Reduce the cone angle a bit to avoid self-collisions
-	const Vec3 randomHemisphere = rotationFromDirection(viewNormal) * hemisphereSampleCos(randomCircle);
-
-	// Trace
-	Vec3 hitPoint;
-	F32 hitAttenuation;
-	const U32 lod = 0u;
-	const F32 minStepf = 4.0;
-	const F32 noise = F32(random.x) * (1.0 / 65536.0);
-	raymarchGroundTruth(viewPos, randomHemisphere, uv, depth, u_unis.m_projMat, u_unis.m_maxSteps, u_depthRt,
-						u_trilinearClampSampler, F32(lod), u_unis.m_depthBufferSize, u_unis.m_firstStepPixels,
-						U32(mix(minStepf, F32(u_unis.m_firstStepPixels), noise)), hitPoint, hitAttenuation);
-
-	// Reject backfacing
-	ANKI_BRANCH if(hitAttenuation > 0.0)
-	{
-		const Vec3 hitNormal =
-			u_unis.m_normalMat * readNormalFromGBuffer(u_gbufferRt2, u_trilinearClampSampler, hitPoint.xy);
-		F32 backFaceAttenuation;
-		rejectBackFaces(randomHemisphere, hitNormal, backFaceAttenuation);
-
-		hitAttenuation *= backFaceAttenuation;
-	}
-
-	// Read the light buffer
-	Vec3 outColor;
-	ANKI_BRANCH if(hitAttenuation > 0.0)
-	{
-		// Reproject the UV because you are reading the previous frame
-		const Vec4 v4 = u_unis.m_prevViewProjMatMulInvViewProjMat * Vec4(UV_TO_NDC(hitPoint.xy), hitPoint.z, 1.0);
-		hitPoint.xy = NDC_TO_UV(v4.xy / v4.w);
-
-		// Read the light buffer
-		outColor = textureLod(u_lightBufferRt, u_trilinearClampSampler, hitPoint.xy, 100.0).rgb;
-		outColor = clamp(outColor, 0.0, FLT_MAX); // Fix the value just in case
-		outColor *= hitAttenuation;
-
-#if 0
-		// Compute a new normal based on the new hit point
-		const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, hitPoint.xy, 0.0).r;
-		const Vec4 viewPos4 = u_unis.m_invProjMat * Vec4(UV_TO_NDC(hitPoint.xy), depth, 1.0);
-		const Vec3 hitViewPos = viewPos4.xyz / viewPos4.w;
-		const Vec3 newViewNormal = normalize(hitViewPos - viewPos);
-#else
-		const Vec3 newViewNormal = viewNormal;
-#endif
-
-		// Modulate
-		const F32 NoL = max(0.0, dot(randomHemisphere, newViewNormal));
-		outColor *= NoL;
-		outColor *= 2.0 * PI;
-	}
-	else
-	{
-		outColor = Vec3(0.0, 0.0, 0.0);
-	}
-
-	// Blend with history
-	{
-		const Vec2 historyUv = uv + textureLod(u_motionVectorsTex, u_trilinearClampSampler, uv, 0.0).rg;
-		const F32 rejection = textureLod(u_motionVectorRejectionTex, u_trilinearClampSampler, uv, 0.0).r;
-		const Vec3 history = textureLod(u_historyTex, u_trilinearClampSampler, historyUv, 0.0).rgb;
-
-		const F32 MAX_BLEND = 0.05;
-		const F32 blend = mix(MAX_BLEND, 1.0, rejection);
-		outColor = mix(history, outColor, blend);
-	}
-
-	// Remove fireflies
-#if 0
-	const Vec3 avgColor = subgroupAdd(outColor) / F32(gl_SubgroupSize);
-	outColor = min(outColor, avgColor);
-#endif
-
-	// Store
-	imageStore(out_img, IVec2(gl_GlobalInvocationID.xy), Vec4(outColor, 1.0));
-}
-
-#pragma anki end

+ 0 - 124
AnKi/Shaders/SsgiDenoise.ankiprog

@@ -1,124 +0,0 @@
-// 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 mutator VARIANT 0 1 2 3
-#pragma anki mutator ORIENTATION 0 1 // 0: VERTICAL, 1: HORIZONTAL
-#pragma anki mutator SAMPLE_COUNT 3 5 7 9 11 13 15
-
-ANKI_SPECIALIZATION_CONSTANT_UVEC2(IN_TEXTURE_SIZE, 0u);
-
-#pragma anki start comp
-
-#include <AnKi/Shaders/BilateralFilter.glsl>
-#include <AnKi/Shaders/PackFunctions.glsl>
-
-#if SAMPLE_COUNT < 3
-#	error See file
-#endif
-
-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 texture2D 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;
-
-layout(std140, push_constant, row_major) uniform b_pc
-{
-	Mat4 u_invViewProjMat;
-};
-
-Vec3 unproject(Vec2 ndc, F32 depth)
-{
-	const Vec4 worldPos4 = u_invViewProjMat * Vec4(ndc, depth, 1.0);
-	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
-	return worldPos;
-}
-
-F32 readDepth(Vec2 uv)
-{
-	return textureLod(u_depthTex, u_linearAnyClampSampler, uv, 0.0).r;
-}
-
-Vec3 readNormal(Vec2 uv)
-{
-	return readNormalFromGBuffer(u_gbuffer2Tex, u_linearAnyClampSampler, uv);
-}
-
-void sampleTex(Vec2 colorUv, Vec2 fullUv, Vec3 positionCenter, Vec3 normalCenter, inout Vec3 col, inout F32 weight)
-{
-	const Vec3 color = textureLod(u_inTex, u_linearAnyClampSampler, colorUv, 0.0).rgb;
-
-	const F32 depthTap = readDepth(fullUv);
-	const Vec3 positionTap = unproject(UV_TO_NDC(fullUv), depthTap);
-	const Vec3 normalTap = readNormal(fullUv);
-
-	F32 w = calculateBilateralWeightPlane(positionCenter, normalCenter, positionTap, normalTap, 0.5);
-	w *= calculateBilateralWeightNormal(normalCenter, normalTap, 0.5);
-	col += color * w;
-	weight += w;
-}
-
-void main()
-{
-	// Set UVs
-	ANKI_BRANCH if(gl_GlobalInvocationID.x >= IN_TEXTURE_SIZE.x || gl_GlobalInvocationID.y >= IN_TEXTURE_SIZE.y)
-	{
-		// Out of bounds
-		return;
-	}
-
-	const Vec2 inUv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(IN_TEXTURE_SIZE);
-#if VARIANT == 0
-	const UVec2 depthReadOffset = UVec2(0, 0);
-#elif VARIANT == 1
-	const UVec2 depthReadOffset = UVec2(1, 0);
-#elif VARIANT == 2
-	const UVec2 depthReadOffset = UVec2(1, 1);
-#else
-	const UVec2 depthReadOffset = UVec2(1, 0);
-#endif
-	const Vec2 depthUv = (Vec2(gl_GlobalInvocationID.xy * 2u + depthReadOffset) + 0.5) / Vec2(IN_TEXTURE_SIZE * 2u);
-
-	const Vec2 IN_TEXEL_SIZE = 1.0 / Vec2(IN_TEXTURE_SIZE);
-	const Vec2 DEPTH_TEXEL_SIZE = 1.0 / Vec2(IN_TEXTURE_SIZE * 2u);
-
-	// Reference
-	Vec3 color = textureLod(u_inTex, u_linearAnyClampSampler, inUv, 0.0).rgb;
-	F32 weight = 1.0;
-
-	const F32 depthCenter = readDepth(depthUv);
-	const Vec3 positionCenter = unproject(UV_TO_NDC(depthUv), depthCenter);
-	const Vec3 normalCenter = readNormal(depthUv);
-
-#if ORIENTATION == 1
-#	define X_OR_Y x
-#else
-#	define X_OR_Y y
-#endif
-
-	Vec2 inUvOffset = Vec2(0.0);
-	inUvOffset.X_OR_Y = 1.0 * IN_TEXEL_SIZE.X_OR_Y;
-	Vec2 depthUvOffset = Vec2(0.0);
-	depthUvOffset.X_OR_Y = 2.0 * DEPTH_TEXEL_SIZE.X_OR_Y;
-
-	ANKI_UNROLL for(U32 i = 0u; i < (U32(SAMPLE_COUNT) - 1u) / 2u; ++i)
-	{
-		sampleTex(inUv + inUvOffset, depthUv + depthUvOffset, positionCenter, normalCenter, color, weight);
-		sampleTex(inUv - inUvOffset, depthUv - depthUvOffset, positionCenter, normalCenter, color, weight);
-
-		inUvOffset.X_OR_Y += IN_TEXEL_SIZE.X_OR_Y;
-		depthUvOffset.X_OR_Y += 2.0 * DEPTH_TEXEL_SIZE.X_OR_Y;
-	}
-
-	color /= weight;
-
-	// Write value
-	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(color, 0.0));
-}
-
-#pragma anki end

+ 0 - 125
AnKi/Shaders/SsgiReconstruct.ankiprog

@@ -1,125 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-// The VARIANT points to the master fragment in the quad:
-// -----
-// |3|2|
-// |0|1|
-// -----
-
-#pragma anki mutator VARIANT 0 1 2 3
-
-ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 0u);
-
-#pragma anki start comp
-
-#include <AnKi/Shaders/Common.glsl>
-
-const UVec2 WORKGROUP_SIZE = UVec2(16u, 16u);
-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_inTex;
-layout(set = 0, binding = 2) uniform texture2D u_depthTex;
-layout(set = 0, binding = 3) writeonly uniform image2D u_outImg;
-
-shared Vec3 s_colors[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
-shared Vec4 s_depths[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
-
-F32 computeDepthWeights(F32 refDepth, F32 depth)
-{
-	const F32 diff = abs(refDepth - depth);
-	const F32 weight = sqrt(1.0 / (EPSILON + diff));
-	return weight;
-}
-
-void reconstruct(IVec2 storeCoord, F32 depthRef, Vec4 colorAndDepth0, Vec4 colorAndDepth1)
-{
-	F32 weight = computeDepthWeights(depthRef, colorAndDepth0.w);
-	Vec3 col = colorAndDepth0.rgb * weight;
-	F32 weightSum = weight;
-
-	weight = computeDepthWeights(depthRef, colorAndDepth1.w);
-	col += colorAndDepth1.rgb * weight;
-	weightSum += weight;
-
-	col /= weightSum;
-
-	imageStore(u_outImg, storeCoord, Vec4(col, 0.0));
-}
-
-void reconstructAll(Vec4 depthRefs, Vec3 masterColor)
-{
-	const IVec2 localInvocationId = IVec2(gl_LocalInvocationID.xy);
-
-#if VARIANT == 0
-	const IVec2 masterStoreCoord = IVec2(gl_GlobalInvocationID.xy * 2u);
-	const IVec2 slaveRelativeCoords[3] = IVec2[](IVec2(1, 0), IVec2(1, 1), IVec2(0, 1));
-	const U32 masterDrefIdx = 3u;
-	const U32 slaveDrefIdx[3] = U32[](2u, 1u, 0u);
-#elif VARIANT == 1
-	const IVec2 masterStoreCoord = IVec2(gl_GlobalInvocationID.xy * 2u) + IVec2(1, 0);
-	const IVec2 slaveRelativeCoords[3] = IVec2[](IVec2(-1, 0), IVec2(0, 1), IVec2(-1, 1));
-	const U32 masterDrefIdx = 2u;
-	const U32 slaveDrefIdx[3] = U32[](3u, 1u, 0u);
-#elif VARIANT == 2
-	const IVec2 masterStoreCoord = IVec2(gl_GlobalInvocationID.xy * 2u) + IVec2(1, 1);
-	const IVec2 slaveRelativeCoords[3] = IVec2[](IVec2(-1, -1), IVec2(0, -1), IVec2(-1, 0));
-	const U32 masterDrefIdx = 1u;
-	const U32 slaveDrefIdx[3] = U32[](3u, 2u, 0u);
-#else
-	const IVec2 masterStoreCoord = IVec2(gl_GlobalInvocationID.xy * 2u) + IVec2(0, 1);
-	const IVec2 slaveRelativeCoords[3] = IVec2[](IVec2(0, -1), IVec2(1, -1), IVec2(1, 0));
-	const U32 masterDrefIdx = 0u;
-	const U32 slaveDrefIdx[3] = U32[](3u, 2u, 1u);
-#endif
-
-	const Vec4 masterColorAndDepth = Vec4(masterColor, depthRefs[masterDrefIdx]);
-	imageStore(u_outImg, masterStoreCoord, Vec4(masterColor, 0.0));
-
-	ANKI_UNROLL for(U32 i = 0u; i < 3u; ++i)
-	{
-		const IVec2 sharedCoord =
-			clamp(localInvocationId + slaveRelativeCoords[i], IVec2(0), IVec2(WORKGROUP_SIZE) - 1);
-		const Vec3 masterColor2 = s_colors[sharedCoord.y][sharedCoord.x];
-		const F32 masterDepth2 = s_depths[sharedCoord.y][sharedCoord.x][masterDrefIdx];
-		const IVec2 storeCoord = masterStoreCoord + slaveRelativeCoords[i];
-		reconstruct(storeCoord, depthRefs[slaveDrefIdx[i]], masterColorAndDepth, Vec4(masterColor2, masterDepth2));
-	}
-}
-
-void main()
-{
-	const UVec2 IN_TEXTURE_SIZE = FB_SIZE / 2u;
-
-	Vec3 color;
-	Vec4 depthRefs;
-	ANKI_BRANCH if(gl_GlobalInvocationID.x < IN_TEXTURE_SIZE.x && gl_GlobalInvocationID.y < IN_TEXTURE_SIZE.y)
-	{
-		const Vec2 inTexelSize = 1.0 / Vec2(IN_TEXTURE_SIZE);
-		const Vec2 fbTexelSize = 1.0 / Vec2(FB_SIZE);
-
-		const Vec2 inUv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(IN_TEXTURE_SIZE);
-		const Vec2 fbUv = (Vec2(gl_GlobalInvocationID.xy) * 2.0 + 1.0) / Vec2(FB_SIZE);
-
-		color = textureLod(u_inTex, u_linearAnyClampSampler, inUv, 0.0).rgb;
-		depthRefs = textureGather(sampler2D(u_depthTex, u_linearAnyClampSampler), fbUv, 0);
-	}
-	else
-	{
-		color = Vec3(0.0);
-		depthRefs = Vec4(1000.0);
-	}
-
-	s_colors[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = color;
-	s_depths[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = depthRefs;
-
-	memoryBarrierShared();
-	barrier();
-
-	reconstructAll(depthRefs, color);
-}
-
-#pragma anki end

+ 1 - 1
AnKi/Shaders/VisualizeRenderTarget.ankiprog

@@ -20,4 +20,4 @@ void main()
 {
 {
 	out_color = textureLod(u_inTex, u_nearestAnyClampSampler, in_uv, 0.0).rgb;
 	out_color = textureLod(u_inTex, u_nearestAnyClampSampler, in_uv, 0.0).rgb;
 }
 }
-#pragma anki end
+#pragma anki end

+ 2 - 1
Samples/Common/Framework.cpp

@@ -74,7 +74,8 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 
 	if(in.getKey(KeyCode::U) == 1)
 	if(in.getKey(KeyCode::U) == 1)
 	{
 	{
-		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "SSGI") ? "" : "SSGI");
+		renderer.setCurrentDebugRenderTarget(
+			(renderer.getCurrentDebugRenderTarget() == "IndirectDiffuse") ? "" : "IndirectDiffuse");
 	}
 	}
 
 
 	if(in.getKey(KeyCode::I) == 1)
 	if(in.getKey(KeyCode::I) == 1)

+ 2 - 0
Samples/Sponza/GenerateAndroidProject.bat

@@ -0,0 +1,2 @@
+cd /D "%~dp0"
+python ../../Tools/Android/GenerateAndroidProject.py -o ../.. -t Sponza -a ./Assets/

+ 2 - 1
Sandbox/Main.cpp

@@ -227,7 +227,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 
 	if(in.getKey(KeyCode::U) == 1)
 	if(in.getKey(KeyCode::U) == 1)
 	{
 	{
-		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "SSGI") ? "" : "SSGI");
+		renderer.setCurrentDebugRenderTarget(
+			(renderer.getCurrentDebugRenderTarget() == "IndirectDiffuse") ? "" : "IndirectDiffuse");
 	}
 	}
 
 
 	if(in.getKey(KeyCode::I) == 1)
 	if(in.getKey(KeyCode::I) == 1)

+ 2 - 0
Tests/GenerateAndroidProject.bat

@@ -0,0 +1,2 @@
+cd /D "%~dp0"
+python ../../Tools/Android/GenerateAndroidProject.py -o .. -t Tests -a ./Assets/