Просмотр исходного кода

Merge pull request #18 from godlikepanos/shader_program_resource

Make SSAO fully temporal
Panagiotis Christopoulos Charitos 8 лет назад
Родитель
Сommit
dd858ebf49

+ 35 - 0
programs/FsFog.ankiprog

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<shaderProgram>
+	<shaders>
+		<shader type="vert">
+			<inputs>
+				<input name="mvp" type="mat4"/>
+			</inputs>
+
+			<source><![CDATA[#include "shaders/FsCommonVert.glsl"
+void main() 
+{
+	ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
+}
+			]]>
+			</source>
+		</shader>
+
+		<shader type="frag">
+			<inputs>
+				<input name="fogColor" type="vec3" const="1"/>
+				<input name="fogScale" type="float" const="1"/>
+			</inputs>
+
+			<source><![CDATA[#include "shaders/FsCommonFrag.glsl"
+void main() 
+{
+	fog(fogColor, fogScale);
+}
+			]]>
+			</source>
+		</shader>
+	</shaders>
+</shaderProgram>
+
+

+ 1 - 1
shaders/Pps.frag.glsl

@@ -134,7 +134,7 @@ void main()
 
 
 #if 0
 #if 0
 	{
 	{
-		out_color = vec3(textureLod(u_isRt, uv, 0.0).rgb);
+		out_color = vec3(textureLod(u_isRt, uv, 0.0).r);
 	}
 	}
 #endif
 #endif
 
 

+ 43 - 29
shaders/Ssao.frag.glsl

@@ -8,9 +8,9 @@
 #include "shaders/Pack.glsl"
 #include "shaders/Pack.glsl"
 #include "shaders/Functions.glsl"
 #include "shaders/Functions.glsl"
 
 
-const vec2 KERNEL[SAMPLES] = KERNEL_ARRAY; // This will be appended in C++
-const float BIAS = 0.2;
-const float STRENGTH = 1.1;
+const float BIAS = 0.3;
+const float STRENGTH = 2.5;
+const float HISTORY_FEEDBACK = 1.0 / 16.0;
 
 
 layout(location = 0) in vec2 in_uv;
 layout(location = 0) in vec2 in_uv;
 
 
@@ -20,11 +20,16 @@ layout(ANKI_UBO_BINDING(0, 0), std140, row_major) uniform _blk
 {
 {
 	vec4 u_unprojectionParams;
 	vec4 u_unprojectionParams;
 	vec4 u_projectionMat;
 	vec4 u_projectionMat;
+	vec4 u_noiseLayerPad3;
+	mat4 u_prevViewProjMatMulInvViewProjMat;
 };
 };
 
 
+#define u_noiseLayer u_noiseLayerPad3.x
+
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_mMsDepthRt;
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_mMsDepthRt;
 layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_msRt;
 layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_msRt;
 layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2DArray u_noiseMap;
 layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2DArray u_noiseMap;
+layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_prevSsaoRt;
 
 
 // Get normal
 // Get normal
 vec3 readNormal(in vec2 uv)
 vec3 readNormal(in vec2 uv)
@@ -35,10 +40,11 @@ vec3 readNormal(in vec2 uv)
 }
 }
 
 
 // Read the noise tex
 // Read the noise tex
-float readRandom(in vec2 uv)
+vec3 readRandom(in vec2 uv)
 {
 {
 	const vec2 tmp = vec2(float(WIDTH) / float(NOISE_MAP_SIZE), float(HEIGHT) / float(NOISE_MAP_SIZE));
 	const vec2 tmp = vec2(float(WIDTH) / float(NOISE_MAP_SIZE), float(HEIGHT) / float(NOISE_MAP_SIZE));
-	return texture(u_noiseMap, vec3(tmp * uv, 0.0)).r;
+	vec3 r = texture(u_noiseMap, vec3(tmp * uv, u_noiseLayer)).rgb;
+	return r;
 }
 }
 
 
 // Returns the Z of the position in view space
 // Returns the Z of the position in view space
@@ -68,13 +74,21 @@ vec4 project(vec4 point)
 void main(void)
 void main(void)
 {
 {
 	vec2 ndc = in_uv * 2.0 - 1.0;
 	vec2 ndc = in_uv * 2.0 - 1.0;
-	vec3 origin = readPosition(in_uv);
+	float depth = texture(u_mMsDepthRt, in_uv).r;
+
+	vec3 origin;
+	origin.z = u_unprojectionParams.z / (u_unprojectionParams.w + depth);
+	origin.xy = ndc * u_unprojectionParams.xy * origin.z;
+
 	vec3 normal = readNormal(in_uv);
 	vec3 normal = readNormal(in_uv);
 
 
-	float randFactor = readRandom(in_uv);
-	float randAng = randFactor * PI * 2.0;
-	float cosAng = cos(randAng);
-	float sinAng = sin(randAng);
+	// Get prev SSAO
+	vec4 clip = u_prevViewProjMatMulInvViewProjMat * vec4(vec3(ndc, UV_TO_NDC(depth)), 1.0);
+	vec2 oldUv = NDC_TO_UV(clip.xy / clip.w);
+	float prevSsao = textureLod(u_prevSsaoRt, oldUv, 0.0).r;
+
+	// Get rand factors
+	vec3 randFactors = readRandom(in_uv);
 
 
 	// Find the projected radius
 	// Find the projected radius
 	vec3 sphereLimit = origin + vec3(RADIUS, 0.0, 0.0);
 	vec3 sphereLimit = origin + vec3(RADIUS, 0.0, 0.0);
@@ -82,24 +96,24 @@ void main(void)
 	vec2 projSphereLimit2 = projSphereLimit.xy / projSphereLimit.w;
 	vec2 projSphereLimit2 = projSphereLimit.xy / projSphereLimit.w;
 	float projRadius = length(projSphereLimit2 - ndc);
 	float projRadius = length(projSphereLimit2 - ndc);
 
 
-	// Integrate
-	float factor = 0.0;
-	for(uint i = 0U; i < SAMPLES; ++i)
-	{
-		// Rotate the disk point
-		vec2 diskPoint = KERNEL[i] * projRadius;
-		vec2 rotDiskPoint;
-		rotDiskPoint.x = diskPoint.x * cosAng - diskPoint.y * sinAng;
-		rotDiskPoint.y = diskPoint.y * cosAng + diskPoint.x * sinAng;
-		vec2 finalDiskPoint = ndc + rotDiskPoint;
-
-		vec3 s = readPosition(NDC_TO_UV(finalDiskPoint));
-		vec3 u = s - origin;
-
-		float f = max(dot(normal, u) + BIAS, 0.0) / max(dot(u, u), EPSILON);
-
-		factor += f;
-	}
+	// Compute rand cos and sin
+	float randAng = randFactors[0] * PI * 2.0;
+	float cosAng = cos(randAng);
+	float sinAng = sin(randAng);
 
 
-	out_color = 1.0 - factor / float(SAMPLES) * STRENGTH;
+	// Rotate the disk point
+	vec2 diskPoint = (randFactors.yz * 0.8 + 0.2) * projRadius;
+	vec2 rotDiskPoint;
+	rotDiskPoint.x = diskPoint.x * cosAng - diskPoint.y * sinAng;
+	rotDiskPoint.y = diskPoint.y * cosAng + diskPoint.x * sinAng;
+	vec2 finalDiskPoint = ndc + rotDiskPoint;
+
+	// Compute factor
+	vec3 s = readPosition(NDC_TO_UV(finalDiskPoint));
+	vec3 u = s - origin;
+	float ssao = max(dot(normal, u) + BIAS, 0.0) / max(dot(u, u), EPSILON);
+	ssao = 1.0 - ssao * STRENGTH;
+
+	// Blend
+	out_color = mix(prevSsao, ssao, HISTORY_FEEDBACK);
 }
 }

+ 1 - 1
src/anki/renderer/Common.h

@@ -51,7 +51,7 @@ const U TILE_SIZE = 64;
 const U FS_FRACTION = 2;
 const U FS_FRACTION = 2;
 
 
 /// SSAO size is rendererSize/SSAO_FRACTION.
 /// SSAO size is rendererSize/SSAO_FRACTION.
-const U SSAO_FRACTION = 4;
+const U SSAO_FRACTION = 2;
 
 
 /// Bloom size is rendererSize/BLOOM_FRACTION.
 /// Bloom size is rendererSize/BLOOM_FRACTION.
 const U BLOOM_FRACTION = 4;
 const U BLOOM_FRACTION = 4;

+ 2 - 2
src/anki/renderer/Is.cpp

@@ -185,8 +185,8 @@ void Is::run(RenderingContext& ctx)
 	cmdb->bindTexture(1, 0, (ctx.m_is.m_diffDecalTex) ? ctx.m_is.m_diffDecalTex : m_r->getDummyTexture());
 	cmdb->bindTexture(1, 0, (ctx.m_is.m_diffDecalTex) ? ctx.m_is.m_diffDecalTex : m_r->getDummyTexture());
 	cmdb->bindTexture(
 	cmdb->bindTexture(
 		1, 1, (ctx.m_is.m_normRoughnessDecalTex) ? ctx.m_is.m_normRoughnessDecalTex : m_r->getDummyTexture());
 		1, 1, (ctx.m_is.m_normRoughnessDecalTex) ? ctx.m_is.m_normRoughnessDecalTex : m_r->getDummyTexture());
-	cmdb->informTextureCurrentUsage(m_r->getSsao().m_main.m_rt, TextureUsageBit::SAMPLED_FRAGMENT);
-	cmdb->bindTexture(1, 2, m_r->getSsao().m_main.m_rt);
+	cmdb->informTextureCurrentUsage(m_r->getSsao().m_main.getPreviousRt(), TextureUsageBit::SAMPLED_FRAGMENT);
+	cmdb->bindTexture(1, 2, m_r->getSsao().m_main.getPreviousRt());
 
 
 	bindUniforms(cmdb, 0, 0, ctx.m_is.m_commonToken);
 	bindUniforms(cmdb, 0, 0, ctx.m_is.m_commonToken);
 	bindUniforms(cmdb, 0, 1, ctx.m_is.m_pointLightsToken);
 	bindUniforms(cmdb, 0, 1, ctx.m_is.m_pointLightsToken);

+ 1 - 0
src/anki/renderer/Pps.cpp

@@ -12,6 +12,7 @@
 #include <anki/renderer/Is.h>
 #include <anki/renderer/Is.h>
 #include <anki/renderer/Ms.h>
 #include <anki/renderer/Ms.h>
 #include <anki/renderer/Dbg.h>
 #include <anki/renderer/Dbg.h>
+#include <anki/renderer/Ssao.h>
 #include <anki/renderer/DownscaleBlur.h>
 #include <anki/renderer/DownscaleBlur.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Logger.h>
 #include <anki/misc/ConfigSet.h>
 #include <anki/misc/ConfigSet.h>

+ 50 - 54
src/anki/renderer/Ssao.cpp

@@ -17,66 +17,50 @@ namespace anki
 
 
 const PixelFormat Ssao::RT_PIXEL_FORMAT(ComponentFormat::R8, TransformFormat::UNORM);
 const PixelFormat Ssao::RT_PIXEL_FORMAT(ComponentFormat::R8, TransformFormat::UNORM);
 
 
-template<typename TVec>
-static void genDisk(TVec* ANKI_RESTRICT arr, TVec* ANKI_RESTRICT arrEnd)
+TexturePtr SsaoMain::getRt() const
 {
 {
-	ANKI_ASSERT(arr && arrEnd && arr < arrEnd);
+	return m_rt[m_r->getFrameCount() & 1];
+}
 
 
-	do
-	{
-		arr->x() = randRange(0.1, 1.0) * 2.0 - 1.0;
-		arr->y() = randRange(0.1, 1.0) * 2.0 - 1.0;
-	} while(++arr != arrEnd);
+TexturePtr SsaoMain::getPreviousRt() const
+{
+	return m_rt[(m_r->getFrameCount() + 1) & 1];
 }
 }
 
 
 Error SsaoMain::init(const ConfigSet& config)
 Error SsaoMain::init(const ConfigSet& config)
 {
 {
-	// RT
-	m_rt = m_r->createAndClearRenderTarget(m_r->create2DRenderTargetInitInfo(m_ssao->m_width,
-		m_ssao->m_height,
-		Ssao::RT_PIXEL_FORMAT,
-		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::CLEAR,
-		SamplingFilter::LINEAR,
-		1,
-		"ssaomain"));
-
-	// FB
-	FramebufferInitInfo fbInit("ssaomain");
-	fbInit.m_colorAttachmentCount = 1;
-	fbInit.m_colorAttachments[0].m_texture = m_rt;
-	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
-	m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
+	for(U i = 0; i < 2; ++i)
+	{
+		// RT
+		m_rt[i] = m_r->createAndClearRenderTarget(m_r->create2DRenderTargetInitInfo(m_ssao->m_width,
+			m_ssao->m_height,
+			Ssao::RT_PIXEL_FORMAT,
+			TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::CLEAR,
+			SamplingFilter::LINEAR,
+			1,
+			"ssaomain"));
+
+		// FB
+		FramebufferInitInfo fbInit("ssaomain");
+		fbInit.m_colorAttachmentCount = 1;
+		fbInit.m_colorAttachments[0].m_texture = m_rt[i];
+		fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
+		m_fb[i] = getGrManager().newInstance<Framebuffer>(fbInit);
+	}
 
 
 	// Noise
 	// Noise
 	ANKI_CHECK(getResourceManager().loadResource("engine_data/BlueNoiseLdrRgb64x64.ankitex", m_noiseTex));
 	ANKI_CHECK(getResourceManager().loadResource("engine_data/BlueNoiseLdrRgb64x64.ankitex", m_noiseTex));
 
 
-	// Kernel
-	StringAuto kernelStr(getAllocator());
-	Array<Vec2, SAMPLES> kernel;
-
-	genDisk(kernel.begin(), kernel.end());
-	kernelStr.create("vec2[](");
-	for(U i = 0; i < kernel.size(); i++)
-	{
-		StringAuto tmp(getAllocator());
-		tmp.sprintf("vec2(%f, %f)%s", kernel[i].x(), kernel[i].y(), (i != kernel.getSize() - 1) ? ", " : ")");
-		kernelStr.append(tmp);
-	}
-
 	// Shader
 	// Shader
 	ANKI_CHECK(m_r->createShaderf("shaders/Ssao.frag.glsl",
 	ANKI_CHECK(m_r->createShaderf("shaders/Ssao.frag.glsl",
 		m_frag,
 		m_frag,
 		"#define NOISE_MAP_SIZE %u\n"
 		"#define NOISE_MAP_SIZE %u\n"
 		"#define WIDTH %u\n"
 		"#define WIDTH %u\n"
 		"#define HEIGHT %u\n"
 		"#define HEIGHT %u\n"
-		"#define SAMPLES %u\n"
-		"#define KERNEL_ARRAY %s\n"
 		"#define RADIUS float(%f)\n",
 		"#define RADIUS float(%f)\n",
 		m_noiseTex->getWidth(),
 		m_noiseTex->getWidth(),
 		m_ssao->m_width,
 		m_ssao->m_width,
 		m_ssao->m_height,
 		m_ssao->m_height,
-		SAMPLES,
-		&kernelStr[0],
 		HEMISPHERE_RADIUS));
 		HEMISPHERE_RADIUS));
 
 
 	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
 	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
@@ -86,27 +70,39 @@ Error SsaoMain::init(const ConfigSet& config)
 
 
 void SsaoMain::setPreRunBarriers(RenderingContext& ctx)
 void SsaoMain::setPreRunBarriers(RenderingContext& ctx)
 {
 {
-	ctx.m_commandBuffer->setTextureSurfaceBarrier(
-		m_rt, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, TextureSurfaceInfo(0, 0, 0, 0));
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt[m_r->getFrameCount() & 1],
+		TextureUsageBit::NONE,
+		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		TextureSurfaceInfo(0, 0, 0, 0));
 }
 }
 
 
 void SsaoMain::run(RenderingContext& ctx)
 void SsaoMain::run(RenderingContext& ctx)
 {
 {
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 
-	cmdb->beginRenderPass(m_fb);
+	cmdb->beginRenderPass(m_fb[m_r->getFrameCount() & 1]);
 	cmdb->setViewport(0, 0, m_ssao->m_width, m_ssao->m_height);
 	cmdb->setViewport(0, 0, m_ssao->m_width, m_ssao->m_height);
 	cmdb->bindShaderProgram(m_prog);
 	cmdb->bindShaderProgram(m_prog);
 
 
 	cmdb->bindTexture(0, 0, m_r->getDepthDownscale().m_qd.m_depthRt);
 	cmdb->bindTexture(0, 0, m_r->getDepthDownscale().m_qd.m_depthRt);
 	cmdb->bindTextureAndSampler(0, 1, m_r->getMs().m_rt2, m_r->getLinearSampler());
 	cmdb->bindTextureAndSampler(0, 1, m_r->getMs().m_rt2, m_r->getLinearSampler());
 	cmdb->bindTexture(0, 2, m_noiseTex->getGrTexture());
 	cmdb->bindTexture(0, 2, m_noiseTex->getGrTexture());
+	cmdb->bindTexture(0, 3, m_rt[(m_r->getFrameCount() + 1) & 1]);
 
 
-	Vec4* unis = allocateAndBindUniforms<Vec4*>(sizeof(Vec4) * 2, cmdb, 0, 0);
+	struct Unis
+	{
+		Vec4 m_unprojectionParams;
+		Vec4 m_projectionMat;
+		Vec4 m_noiseLayerPad3;
+		Mat4 m_prevViewProjMatMulInvViewProjMat;
+	};
+
+	Unis* unis = allocateAndBindUniforms<Unis*>(sizeof(Unis), cmdb, 0, 0);
 	const Mat4& pmat = ctx.m_projMat;
 	const Mat4& pmat = ctx.m_projMat;
-	*unis = ctx.m_unprojParams;
-	++unis;
-	*unis = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
+	unis->m_unprojectionParams = ctx.m_unprojParams;
+	unis->m_projectionMat = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
+	unis->m_noiseLayerPad3 = Vec4(m_r->getFrameCount() % m_noiseTex->getLayerCount(), 0.0, 0.0, 0.0);
+	unis->m_prevViewProjMatMulInvViewProjMat = ctx.m_prevViewProjMat * ctx.m_viewProjMat.getInverse();
 
 
 	m_r->drawQuad(cmdb);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
 	cmdb->endRenderPass();
@@ -114,7 +110,7 @@ void SsaoMain::run(RenderingContext& ctx)
 
 
 void SsaoMain::setPostRunBarriers(RenderingContext& ctx)
 void SsaoMain::setPostRunBarriers(RenderingContext& ctx)
 {
 {
-	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt,
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt[m_r->getFrameCount() & 1],
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureSurfaceInfo(0, 0, 0, 0));
 		TextureSurfaceInfo(0, 0, 0, 0));
@@ -144,7 +140,7 @@ Error SsaoHBlur::init(const ConfigSet& config)
 		"#define HPASS\n"
 		"#define HPASS\n"
 		"#define COL_R\n"
 		"#define COL_R\n"
 		"#define TEXTURE_SIZE vec2(%f, %f)\n"
 		"#define TEXTURE_SIZE vec2(%f, %f)\n"
-		"#define KERNEL_SIZE 11\n",
+		"#define KERNEL_SIZE 5\n",
 		F32(m_ssao->m_width),
 		F32(m_ssao->m_width),
 		F32(m_ssao->m_height)));
 		F32(m_ssao->m_height)));
 
 
@@ -166,7 +162,7 @@ void SsaoHBlur::run(RenderingContext& ctx)
 	cmdb->setViewport(0, 0, m_ssao->m_width, m_ssao->m_height);
 	cmdb->setViewport(0, 0, m_ssao->m_width, m_ssao->m_height);
 	cmdb->beginRenderPass(m_fb);
 	cmdb->beginRenderPass(m_fb);
 	cmdb->bindShaderProgram(m_prog);
 	cmdb->bindShaderProgram(m_prog);
-	cmdb->bindTexture(0, 0, m_ssao->m_main.m_rt);
+	cmdb->bindTexture(0, 0, m_ssao->m_main.m_rt[m_r->getFrameCount() & 1]);
 	m_r->drawQuad(cmdb);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
 	cmdb->endRenderPass();
 }
 }
@@ -186,7 +182,7 @@ Error SsaoVBlur::init(const ConfigSet& config)
 		"#define VPASS\n"
 		"#define VPASS\n"
 		"#define COL_R\n"
 		"#define COL_R\n"
 		"#define TEXTURE_SIZE vec2(%f, %f)\n"
 		"#define TEXTURE_SIZE vec2(%f, %f)\n"
-		"#define KERNEL_SIZE 9\n",
+		"#define KERNEL_SIZE 5\n",
 		F32(m_ssao->m_width),
 		F32(m_ssao->m_width),
 		F32(m_ssao->m_height)));
 		F32(m_ssao->m_height)));
 
 
@@ -197,7 +193,7 @@ Error SsaoVBlur::init(const ConfigSet& config)
 
 
 void SsaoVBlur::setPreRunBarriers(RenderingContext& ctx)
 void SsaoVBlur::setPreRunBarriers(RenderingContext& ctx)
 {
 {
-	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_ssao->m_main.m_rt,
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_ssao->m_main.m_rt[m_r->getFrameCount() & 1],
 		TextureUsageBit::NONE,
 		TextureUsageBit::NONE,
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureSurfaceInfo(0, 0, 0, 0));
 		TextureSurfaceInfo(0, 0, 0, 0));
@@ -208,7 +204,7 @@ void SsaoVBlur::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 
 	cmdb->setViewport(0, 0, m_ssao->m_width, m_ssao->m_height);
 	cmdb->setViewport(0, 0, m_ssao->m_width, m_ssao->m_height);
-	cmdb->beginRenderPass(m_ssao->m_main.m_fb);
+	cmdb->beginRenderPass(m_ssao->m_main.m_fb[m_r->getFrameCount() & 1]);
 	cmdb->bindShaderProgram(m_prog);
 	cmdb->bindShaderProgram(m_prog);
 	cmdb->bindTexture(0, 0, m_ssao->m_hblur.m_rt);
 	cmdb->bindTexture(0, 0, m_ssao->m_hblur.m_rt);
 	m_r->drawQuad(cmdb);
 	m_r->drawQuad(cmdb);
@@ -217,7 +213,7 @@ void SsaoVBlur::run(RenderingContext& ctx)
 
 
 void SsaoVBlur::setPostRunBarriers(RenderingContext& ctx)
 void SsaoVBlur::setPostRunBarriers(RenderingContext& ctx)
 {
 {
-	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_ssao->m_main.m_rt,
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_ssao->m_main.m_rt[m_r->getFrameCount() & 1],
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureSurfaceInfo(0, 0, 0, 0));
 		TextureSurfaceInfo(0, 0, 0, 0));

+ 7 - 4
src/anki/renderer/Ssao.h

@@ -24,12 +24,10 @@ class Ssao;
 class SsaoMain : public RenderingPass
 class SsaoMain : public RenderingPass
 {
 {
 	friend class SsaoVBlur;
 	friend class SsaoVBlur;
+	friend class SsaoHBlur;
 
 
 anki_internal:
 anki_internal:
 	static constexpr F32 HEMISPHERE_RADIUS = 3.0; // In game units
 	static constexpr F32 HEMISPHERE_RADIUS = 3.0; // In game units
-	static const U SAMPLES = 8;
-
-	TexturePtr m_rt;
 
 
 	SsaoMain(Renderer* r, Ssao* ssao)
 	SsaoMain(Renderer* r, Ssao* ssao)
 		: RenderingPass(r)
 		: RenderingPass(r)
@@ -37,6 +35,10 @@ anki_internal:
 	{
 	{
 	}
 	}
 
 
+	TexturePtr getRt() const;
+
+	TexturePtr getPreviousRt() const;
+
 	ANKI_USE_RESULT Error init(const ConfigSet& config);
 	ANKI_USE_RESULT Error init(const ConfigSet& config);
 
 
 	void setPreRunBarriers(RenderingContext& ctx);
 	void setPreRunBarriers(RenderingContext& ctx);
@@ -48,7 +50,8 @@ anki_internal:
 private:
 private:
 	Ssao* m_ssao;
 	Ssao* m_ssao;
 
 
-	FramebufferPtr m_fb;
+	Array<TexturePtr, 2> m_rt;
+	Array<FramebufferPtr, 2> m_fb;
 	ShaderResourcePtr m_frag;
 	ShaderResourcePtr m_frag;
 	ShaderProgramPtr m_prog;
 	ShaderProgramPtr m_prog;
 	TextureResourcePtr m_noiseTex;
 	TextureResourcePtr m_noiseTex;