Browse Source

Move the blur of SSAO to compute as well

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
a4691b13ca

+ 4 - 2
programs/DepthAwareBlur.ankiprog

@@ -6,7 +6,7 @@ http://www.anki3d.org/LICENSE
 -->
 <shaderProgram>
 	<mutators>
-		<mutator name="ORIENTATION" values="0 1"/> <!-- 0: VERTICAL, 1: HORIZONTAL -->
+		<mutator name="ORIENTATION" values="0 1 2"/> <!-- 0: VERTICAL, 1: HORIZONTAL, 2: BOX -->
 		<mutator name="SAMPLE_COUNT" values="3 5 7 9 11 13 15"/>
 		<mutator name="COLOR_COMPONENTS" values="4 3 1"/>
 	</mutators>
@@ -26,8 +26,10 @@ http://www.anki3d.org/LICENSE
 			<source><![CDATA[
 #if ORIENTATION == 0
 #	define VERTICAL 1
-#else
+#elif ORIENTATION == 1
 #	define HORIZONTAL 1
+#else
+#	define BOX 1
 #endif
 
 #include "shaders/DepthAwareBlur.glsl"

+ 34 - 0
programs/DepthAwareBlurCompute.ankiprog

@@ -0,0 +1,34 @@
+<!-- 
+Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+All rights reserved.
+Code licensed under the BSD License.
+http://www.anki3d.org/LICENSE
+-->
+<shaderProgram>
+	<mutators>
+		<mutator name="ORIENTATION" values="0 1 2"/> <!-- 0: VERTICAL, 1: HORIZONTAL, 2: BOX -->
+		<mutator name="SAMPLE_COUNT" values="3 5 7 9 11 13 15"/>
+		<mutator name="COLOR_COMPONENTS" values="4 3 1"/>
+	</mutators>
+
+	<shaders>
+		<shader type="comp">
+			<inputs>
+				<input name="TEXTURE_SIZE" type="uvec2" const="1"/>
+				<input name="WORKGROUP_SIZE" type="uvec2" const="1"/>
+			</inputs>
+
+			<source><![CDATA[
+#if ORIENTATION == 0
+#	define VERTICAL 1
+#elif ORIENTATION == 1
+#	define HORIZONTAL 1
+#else
+#	define BOX 1
+#endif
+
+#include "shaders/DepthAwareBlur.glsl"
+			]]></source>
+		</shader>
+	</shaders>
+</shaderProgram>

+ 140 - 0
shaders/DepthAwareBlur.glsl

@@ -0,0 +1,140 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// Defines it needs:
+// HORIZONTAL | VERTICAL | BOX
+// COLOR_COMPONENTS
+// WORKGROUP_SIZE (only for compute)
+// TEXTURE_SIZE
+// SAMPLE_COUNT (must be odd number)
+
+#ifndef ANKI_SHADERS_DEPTH_AWARE_BLUR_GLSL
+#define ANKI_SHADERS_DEPTH_AWARE_BLUR_GLSL
+
+#include "shaders/Common.glsl"
+
+#if SAMPLE_COUNT < 3
+#	error See file
+#endif
+
+#if defined(ANKI_COMPUTE_SHADER)
+#	define USE_COMPUTE 1
+#else
+#	define USE_COMPUTE 0
+#endif
+
+// Define some macros depending on the number of components
+#if COLOR_COMPONENTS == 4
+#	define COL_TYPE vec4
+#	define TEX_FETCH rgba
+#	define TO_VEC4(x_) x_
+#elif COLOR_COMPONENTS == 3
+#	define COL_TYPE vec3
+#	define TEX_FETCH rgb
+#	define TO_VEC4(x_) vec4(x_, 0.0)
+#elif COLOR_COMPONENTS == 1
+#	define COL_TYPE float
+#	define TEX_FETCH r
+#	define TO_VEC4(x_) vec4(x_, 0.0, 0.0, 0.0)
+#else
+#	error See file
+#endif
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_inTex;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_depthTex;
+
+#if USE_COMPUTE
+layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
+layout(ANKI_IMAGE_BINDING(0, 0)) writeonly uniform image2D u_outImg;
+#else
+layout(location = 0) in vec2 in_uv;
+layout(location = 0) out COL_TYPE out_color;
+#endif
+
+float computeDepthWeight(float refDepth, float depth)
+{
+	float diff = abs(refDepth - depth);
+	float weight = 1.0 / (EPSILON + diff);
+	return sqrt(weight);
+}
+
+float readDepth(vec2 uv)
+{
+	return textureLod(u_depthTex, uv, 0.0).r;
+}
+
+void sampleTex(vec2 uv, float refDepth, inout COL_TYPE col, inout float weight)
+{
+	COL_TYPE color = textureLod(u_inTex, uv, 0.0).TEX_FETCH;
+	float w = computeDepthWeight(refDepth, readDepth(uv));
+	col += color * w;
+	weight += w;
+}
+
+void main()
+{
+	// Compute texel size
+#if defined(HORIZONTAL)
+	const vec2 TEXEL_SIZE = vec2(1.0 / float(TEXTURE_SIZE.x), 0.0);
+#elif defined(VERTICAL)
+	const vec2 TEXEL_SIZE = vec2(0.0, 1.0 / float(TEXTURE_SIZE.y));
+#endif
+
+	// Set UVs
+#if USE_COMPUTE
+	ANKI_BRANCH if(gl_GlobalInvocationID.x >= TEXTURE_SIZE.x || gl_GlobalInvocationID.y >= TEXTURE_SIZE.y)
+	{
+		// Out of bounds
+		return;
+	}
+
+	vec2 uv = (vec2(gl_GlobalInvocationID.xy) + 0.5) / vec2(TEXTURE_SIZE);
+#else
+	vec2 uv = in_uv;
+#endif
+
+	// Sample
+	COL_TYPE color = textureLod(u_inTex, uv, 0.0).TEX_FETCH;
+	float refDepth = readDepth(uv);
+	float weight = 1.0;
+
+#if !defined(BOX)
+	// Do seperable
+
+	vec2 texCoordOffset = 1.5 * TEXEL_SIZE;
+
+	ANKI_UNROLL for(uint i = 0u; i < (SAMPLE_COUNT - 1u) / 2u; ++i)
+	{
+		sampleTex(uv + texCoordOffset, refDepth, color, weight);
+		sampleTex(uv - texCoordOffset, refDepth, color, weight);
+
+		texCoordOffset += 2.0 * TEXEL_SIZE;
+	}
+#else
+	// Do box
+
+	const vec2 OFFSET = 1.5 * (1.0 / vec2(TEXTURE_SIZE));
+
+	sampleTex(uv + vec2(+OFFSET.x, +OFFSET.y), refDepth, color, weight);
+	sampleTex(uv + vec2(+OFFSET.x, -OFFSET.y), refDepth, color, weight);
+	sampleTex(uv + vec2(-OFFSET.x, +OFFSET.y), refDepth, color, weight);
+	sampleTex(uv + vec2(-OFFSET.x, -OFFSET.y), refDepth, color, weight);
+
+	sampleTex(uv + vec2(OFFSET.x, 0.0), refDepth, color, weight);
+	sampleTex(uv + vec2(0.0, OFFSET.y), refDepth, color, weight);
+	sampleTex(uv + vec2(-OFFSET.x, 0.0), refDepth, color, weight);
+	sampleTex(uv + vec2(0.0, -OFFSET.y), refDepth, color, weight);
+#endif
+	color = color / weight;
+
+	// Write value
+#if USE_COMPUTE
+	imageStore(u_outImg, ivec2(gl_GlobalInvocationID.xy), TO_VEC4(color));
+#else
+	out_color = color;
+#endif
+}
+
+#endif

+ 1 - 1
shaders/Ssao.glsl

@@ -149,7 +149,7 @@ void main(void)
 		return;
 	}
 
-	vec2 uv = vec2(gl_GlobalInvocationID.xy) / vec2(FB_SIZE);
+	vec2 uv = (vec2(gl_GlobalInvocationID.xy) + 0.5) / vec2(FB_SIZE);
 #else
 	vec2 uv = in_uv;
 #endif

+ 67 - 68
src/anki/renderer/Ssao.cpp

@@ -51,38 +51,38 @@ Error Ssao::initMain(const ConfigSet& config)
 	return Error::NONE;
 }
 
-Error Ssao::initHBlur(const ConfigSet& config)
+Error Ssao::initBlur(const ConfigSet& config)
 {
 	// shader
-	ANKI_CHECK(m_r->getResourceManager().loadResource("programs/DepthAwareBlur.ankiprog", m_hblur.m_prog));
-
-	ShaderProgramResourceMutationInitList<3> mutators(m_hblur.m_prog);
-	mutators.add("ORIENTATION", 1).add("SAMPLE_COUNT", 9).add("COLOR_COMPONENTS", 1);
-	ShaderProgramResourceConstantValueInitList<1> consts(m_hblur.m_prog);
-	consts.add("TEXTURE_SIZE", UVec2(m_width, m_height));
-
-	const ShaderProgramResourceVariant* variant;
-	m_hblur.m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
+	if(m_blurUseCompute)
+	{
+		ANKI_CHECK(m_r->getResourceManager().loadResource("programs/DepthAwareBlurCompute.ankiprog", m_blur.m_prog));
 
-	m_hblur.m_grProg = variant->getProgram();
+		ShaderProgramResourceMutationInitList<3> mutators(m_blur.m_prog);
+		mutators.add("ORIENTATION", 2).add("SAMPLE_COUNT", 3).add("COLOR_COMPONENTS", 1);
+		ShaderProgramResourceConstantValueInitList<2> consts(m_blur.m_prog);
+		consts.add("TEXTURE_SIZE", UVec2(m_width, m_height))
+			.add("WORKGROUP_SIZE", UVec2(m_workgroupSize[0], m_workgroupSize[1]));
 
-	return Error::NONE;
-}
+		const ShaderProgramResourceVariant* variant;
+		m_blur.m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
 
-Error Ssao::initVBlur(const ConfigSet& config)
-{
-	// shader
-	ANKI_CHECK(m_r->getResourceManager().loadResource("programs/DepthAwareBlur.ankiprog", m_vblur.m_prog));
+		m_blur.m_grProg = variant->getProgram();
+	}
+	else
+	{
+		ANKI_CHECK(m_r->getResourceManager().loadResource("programs/DepthAwareBlur.ankiprog", m_blur.m_prog));
 
-	ShaderProgramResourceMutationInitList<3> mutators(m_vblur.m_prog);
-	mutators.add("ORIENTATION", 0).add("SAMPLE_COUNT", 9).add("COLOR_COMPONENTS", 1);
-	ShaderProgramResourceConstantValueInitList<1> consts(m_vblur.m_prog);
-	consts.add("TEXTURE_SIZE", UVec2(m_width, m_height));
+		ShaderProgramResourceMutationInitList<3> mutators(m_blur.m_prog);
+		mutators.add("ORIENTATION", 2).add("SAMPLE_COUNT", 3).add("COLOR_COMPONENTS", 1);
+		ShaderProgramResourceConstantValueInitList<1> consts(m_blur.m_prog);
+		consts.add("TEXTURE_SIZE", UVec2(m_width, m_height));
 
-	const ShaderProgramResourceVariant* variant;
-	m_vblur.m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
+		const ShaderProgramResourceVariant* variant;
+		m_blur.m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
 
-	m_vblur.m_grProg = variant->getProgram();
+		m_blur.m_grProg = variant->getProgram();
+	}
 
 	return Error::NONE;
 }
@@ -98,16 +98,17 @@ Error Ssao::init(const ConfigSet& config)
 	m_rtDescrs[0] = m_r->create2DRenderTargetDescription(m_width,
 		m_height,
 		Ssao::RT_PIXEL_FORMAT,
-		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE
-			| ((m_useCompute) ? TextureUsageBit::IMAGE_COMPUTE_WRITE : TextureUsageBit::NONE),
-		"SSAO_0");
+		((m_blurUseCompute) ? TextureUsageBit::SAMPLED_COMPUTE : TextureUsageBit::SAMPLED_FRAGMENT)
+			| ((m_useCompute) ? TextureUsageBit::IMAGE_COMPUTE_WRITE : TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE),
+		"SSAOMain");
 	m_rtDescrs[0].bake();
 
 	m_rtDescrs[1] = m_r->create2DRenderTargetDescription(m_width,
 		m_height,
 		Ssao::RT_PIXEL_FORMAT,
-		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
-		"SSAO_1");
+		((m_blurUseCompute) ? TextureUsageBit::IMAGE_COMPUTE_WRITE : TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE)
+			| TextureUsageBit::SAMPLED_FRAGMENT,
+		"SSAOBlur");
 	m_rtDescrs[1].bake();
 
 	// FB descr
@@ -119,12 +120,7 @@ Error Ssao::init(const ConfigSet& config)
 
 	if(!err)
 	{
-		err = initHBlur(config);
-	}
-
-	if(!err)
-	{
-		err = initVBlur(config);
+		err = initBlur(config);
 	}
 
 	if(err)
@@ -182,28 +178,28 @@ void Ssao::runMain(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx
 	}
 }
 
-void Ssao::runHBlur(RenderPassWorkContext& rgraphCtx)
+void Ssao::runBlur(RenderPassWorkContext& rgraphCtx)
 {
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
-	cmdb->setViewport(0, 0, m_width, m_height);
-	cmdb->bindShaderProgram(m_hblur.m_grProg);
+	cmdb->bindShaderProgram(m_blur.m_grProg);
 	rgraphCtx.bindColorTextureAndSampler(0, 0, m_runCtx.m_rts[0], m_r->getLinearSampler());
 	rgraphCtx.bindTextureAndSampler(
 		0, 1, m_r->getDepthDownscale().getHiZRt(), HIZ_QUARTER_DEPTH, m_r->getLinearSampler());
-	drawQuad(cmdb);
-}
 
-void Ssao::runVBlur(RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	if(m_blurUseCompute)
+	{
+		rgraphCtx.bindImage(0, 0, m_runCtx.m_rts[1], TextureSubresourceInfo());
 
-	cmdb->setViewport(0, 0, m_width, m_height);
-	cmdb->bindShaderProgram(m_vblur.m_grProg);
-	rgraphCtx.bindColorTextureAndSampler(0, 0, m_runCtx.m_rts[1], m_r->getLinearSampler());
-	rgraphCtx.bindTextureAndSampler(
-		0, 1, m_r->getDepthDownscale().getHiZRt(), HIZ_QUARTER_DEPTH, m_r->getLinearSampler());
-	drawQuad(cmdb);
+		const U sizeX = (m_width + m_workgroupSize[0] - 1) / m_workgroupSize[0];
+		const U sizeY = (m_height + m_workgroupSize[1] - 1) / m_workgroupSize[1];
+		cmdb->dispatchCompute(sizeX, sizeY, 1);
+	}
+	else
+	{
+		cmdb->setViewport(0, 0, m_width, m_height);
+		drawQuad(cmdb);
+	}
 }
 
 void Ssao::populateRenderGraph(RenderingContext& ctx)
@@ -253,30 +249,33 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 		}
 	}
 
-	// Create HBlur pass
+	// Create Blur pass
 	{
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO hblur");
-
-		pass.setWork(runHBlurCallback, this, 0);
-		pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[1]}}, {});
+		if(m_blurUseCompute)
+		{
+			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("SSAO blur");
 
-		pass.newConsumer({m_runCtx.m_rts[1], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-		pass.newConsumer({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_FRAGMENT});
-		pass.newConsumer({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_FRAGMENT, HIZ_QUARTER_DEPTH});
-		pass.newProducer({m_runCtx.m_rts[1], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-	}
+			pass.setWork(runBlurCallback, this, 0);
 
-	// Create VBlur pass
-	{
-		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO vblur");
+			pass.newConsumer(
+				{m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_COMPUTE, HIZ_QUARTER_DEPTH});
+			pass.newConsumer({m_runCtx.m_rts[1], TextureUsageBit::IMAGE_COMPUTE_WRITE});
+			pass.newConsumer({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_COMPUTE});
+			pass.newProducer({m_runCtx.m_rts[1], TextureUsageBit::IMAGE_COMPUTE_WRITE});
+		}
+		else
+		{
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO blur");
 
-		pass.setWork(runVBlurCallback, this, 0);
-		pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[0]}}, {});
+			pass.setWork(runBlurCallback, this, 0);
+			pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[1]}}, {});
 
-		pass.newConsumer({m_runCtx.m_rts[0], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-		pass.newConsumer({m_runCtx.m_rts[1], TextureUsageBit::SAMPLED_FRAGMENT});
-		pass.newConsumer({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_FRAGMENT, HIZ_QUARTER_DEPTH});
-		pass.newProducer({m_runCtx.m_rts[0], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
+			pass.newConsumer({m_runCtx.m_rts[1], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
+			pass.newConsumer({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_FRAGMENT});
+			pass.newConsumer(
+				{m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_FRAGMENT, HIZ_QUARTER_DEPTH});
+			pass.newProducer({m_runCtx.m_rts[1], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
+		}
 	}
 }
 

+ 8 - 23
src/anki/renderer/Ssao.h

@@ -35,13 +35,14 @@ anki_internal:
 
 	RenderTargetHandle getRt() const
 	{
-		return m_runCtx.m_rts[0];
+		return m_runCtx.m_rts[1];
 	}
 
 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;
 	Array<U32, 2> m_workgroupSize = {{16, 16}};
 
@@ -58,14 +59,7 @@ private:
 	public:
 		ShaderProgramResourcePtr m_prog;
 		ShaderProgramPtr m_grProg;
-	} m_hblur; ///< Horizontal blur.
-
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		ShaderProgramPtr m_grProg;
-	} m_vblur; ///< Vertical blur.
+	} m_blur; ///< Box blur.
 
 	class
 	{
@@ -78,12 +72,10 @@ private:
 	FramebufferDescription m_fbDescr;
 
 	ANKI_USE_RESULT Error initMain(const ConfigSet& set);
-	ANKI_USE_RESULT Error initVBlur(const ConfigSet& set);
-	ANKI_USE_RESULT Error initHBlur(const ConfigSet& set);
+	ANKI_USE_RESULT Error initBlur(const ConfigSet& set);
 
 	void runMain(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
-	void runHBlur(RenderPassWorkContext& rgraphCtx);
-	void runVBlur(RenderPassWorkContext& rgraphCtx);
+	void runBlur(RenderPassWorkContext& rgraphCtx);
 
 	/// A RenderPassWorkCallback for SSAO main pass.
 	static void runMainCallback(RenderPassWorkContext& rgraphCtx)
@@ -92,18 +84,11 @@ private:
 		self->runMain(*self->m_runCtx.m_ctx, rgraphCtx);
 	}
 
-	/// A RenderPassWorkCallback for SSAO HBlur.
-	static void runHBlurCallback(RenderPassWorkContext& rgraphCtx)
-	{
-		Ssao* const self = scast<Ssao*>(rgraphCtx.m_userData);
-		self->runHBlur(rgraphCtx);
-	}
-
-	/// A RenderPassWorkCallback for SSAO VBlur.
-	static void runVBlurCallback(RenderPassWorkContext& rgraphCtx)
+	/// A RenderPassWorkCallback for SSAO blur.
+	static void runBlurCallback(RenderPassWorkContext& rgraphCtx)
 	{
 		Ssao* const self = scast<Ssao*>(rgraphCtx.m_userData);
-		self->runVBlur(rgraphCtx);
+		self->runBlur(rgraphCtx);
 	}
 };
 /// @}