Browse Source

Renderer: Add proper upsample for volumetric

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
c8de9d57ee

+ 12 - 3
shaders/DepthDownscale.frag.glsl

@@ -9,12 +9,21 @@ layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_depthRt;
 
 layout(location = 0) in vec2 in_uv;
 
+#define AVG
+
 void main()
 {
 	vec4 depths = textureGather(u_depthRt, in_uv, 0);
 
+#if defined(MIN)
 	vec2 mind2 = min(depths.xy, depths.zw);
-	float mind = min(mind2.x, mind2.y);
-
-	gl_FragDepth = mind;
+	gl_FragDepth = min(mind2.x, mind2.y);
+#elif defined(MAX)
+	vec2 max2 = max(depths.xy, depths.zw);
+	gl_FragDepth = max(max2.x, max2.y);
+#elif defined(AVG)
+	gl_FragDepth = dot(depths, vec4(1.0 / 4.0));
+#else
+#error See file
+#endif
 }

+ 3 - 50
shaders/FsUpscale.frag.glsl

@@ -13,63 +13,16 @@ layout(location = 0) out vec4 out_color;
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_depthFullTex;
 layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_depthHalfTex;
 layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_fsRt;
-layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_volTex;
 #if SSAO_ENABLED
-layout(ANKI_TEX_BINDING(0, 4)) uniform sampler2D u_ssaoTex;
+layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_ssaoTex;
 #endif
 
-layout(ANKI_UBO_BINDING(0, 0)) uniform _u0
-{
-	vec4 u_linearizePad2;
-};
-
-const float DEPTH_THRESHOLD = 1.0 / 1000.0;
-
-const vec2 COLOR_TEX_TEXEL_SIZE = 1.0 / vec2(TEXTURE_WIDTH, TEXTURE_HEIGHT);
+const float DEPTH_THRESHOLD = 1.0 / 4000.0;
 
 void main()
 {
 	// Get the depth of the current fragment
-	float depth = texture(u_depthFullTex, in_uv).r;
-	vec3 color = textureLod(u_volTex, in_uv, 0.0).rgb;
-
-	vec4 lowDepths = textureGather(u_depthHalfTex, in_uv, 0);
-	vec4 diffs = abs(vec4(depth) - lowDepths);
-
-	if(all(lessThan(diffs, vec4(DEPTH_THRESHOLD))))
-	{
-		// No major discontinuites, sample with bilinear
-		color += textureLod(u_fsRt, in_uv, 0.0).rgb;
-	}
-	else
-	{
-		// Some discontinuites, need to use the newUv
-		vec4 r = textureGather(u_fsRt, in_uv, 0);
-		vec4 g = textureGather(u_fsRt, in_uv, 1);
-		vec4 b = textureGather(u_fsRt, in_uv, 2);
-
-		float minDiff = diffs.x;
-		uint comp = 0;
-
-		if(diffs.y < minDiff)
-		{
-			comp = 1;
-			minDiff = diffs.y;
-		}
-
-		if(diffs.z < minDiff)
-		{
-			comp = 2;
-			minDiff = diffs.z;
-		}
-
-		if(diffs.w < minDiff)
-		{
-			comp = 3;
-		}
-
-		color += vec3(r[comp], g[comp], b[comp]);
-	}
+	vec3 color = nearestDepthUpscale(in_uv, u_depthFullTex, u_depthHalfTex, u_fsRt, DEPTH_THRESHOLD);
 
 #if SSAO_ENABLED
 	float ssao = textureLod(u_ssaoTex, in_uv, 0.0).r;

+ 45 - 0
shaders/Functions.glsl

@@ -74,4 +74,49 @@ float rand(vec2 n)
 	return 0.5 + 0.5 * fract(sin(dot(n, vec2(12.9898, 78.233))) * 43758.5453);
 }
 
+vec3 nearestDepthUpscale(vec2 uv, sampler2D depthFull, sampler2D depthHalf, sampler2D colorTex, float depthThreshold)
+{
+	float fullDepth = texture(depthFull, uv).r;
+	vec4 halfDepths = textureGather(depthHalf, uv, 0);
+	vec4 diffs = abs(vec4(fullDepth) - halfDepths);
+	vec3 color;
+
+	if(all(lessThan(diffs, vec4(depthThreshold))))
+	{
+		// No major discontinuites, sample with bilinear
+		color = texture(colorTex, uv).rgb;
+	}
+	else
+	{
+		// Some discontinuites, need to use the newUv
+		vec4 r = textureGather(colorTex, uv, 0);
+		vec4 g = textureGather(colorTex, uv, 1);
+		vec4 b = textureGather(colorTex, uv, 2);
+
+		float minDiff = diffs.x;
+		uint comp = 0;
+
+		if(diffs.y < minDiff)
+		{
+			comp = 1;
+			minDiff = diffs.y;
+		}
+
+		if(diffs.z < minDiff)
+		{
+			comp = 2;
+			minDiff = diffs.z;
+		}
+
+		if(diffs.w < minDiff)
+		{
+			comp = 3;
+		}
+
+		color = vec3(r[comp], g[comp], b[comp]);
+	}
+
+	return color;
+}
+
 #endif

+ 1 - 1
shaders/Pps.frag.glsl

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

+ 20 - 0
shaders/VolumetricUpscale.frag.glsl

@@ -0,0 +1,20 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "shaders/Functions.glsl"
+
+layout(location = 0) in vec2 in_uv;
+layout(location = 0) out vec3 out_color;
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_depthFullTex;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_depthHalfTex;
+layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_colorTex;
+
+const float DEPTH_THRESHOLD = 1.0 / 5000.0;
+
+void main()
+{
+	out_color = nearestDepthUpscale(in_uv, u_depthFullTex, u_depthHalfTex, u_colorTex, DEPTH_THRESHOLD);
+}

+ 27 - 1
src/anki/renderer/Fs.cpp

@@ -8,6 +8,7 @@
 #include <anki/renderer/Ms.h>
 #include <anki/renderer/Is.h>
 #include <anki/renderer/Sm.h>
+#include <anki/renderer/Volumetric.h>
 #include <anki/renderer/DepthDownscale.h>
 #include <anki/scene/SceneGraph.h>
 #include <anki/scene/FrustumComponent.h>
@@ -93,11 +94,36 @@ Error Fs::init(const ConfigSet&)
 
 Error Fs::initVol()
 {
-	// TODO
+	ANKI_CHECK(getResourceManager().loadResource("shaders/VolumetricUpscale.frag.glsl", m_vol.m_frag));
+
+	ColorStateInfo color;
+	color.m_attachmentCount = 1;
+	color.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
+	color.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
+	color.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE;
+	m_r->createDrawQuadPipeline(m_vol.m_frag->getGrShader(), color, m_vol.m_ppline);
+
+	SamplerInitInfo sinit;
+	sinit.m_repeat = false;
+	sinit.m_mipmapFilter = SamplingFilter::NEAREST;
+
+	ResourceGroupInitInfo rcinit;
+	rcinit.m_textures[0].m_texture = m_r->getDepthDownscale().m_hd.m_depthRt;
+	rcinit.m_textures[0].m_sampler = getGrManager().newInstance<Sampler>(sinit);
+	rcinit.m_textures[1].m_texture = m_r->getDepthDownscale().m_qd.m_depthRt;
+	rcinit.m_textures[2].m_texture = m_r->getVolumetric().m_rt;
+	m_vol.m_rc = getGrManager().newInstance<ResourceGroup>(rcinit);
 
 	return ErrorCode::NONE;
 }
 
+void Fs::drawVolumetric(RenderingContext& ctx, CommandBufferPtr cmdb)
+{
+	cmdb->bindPipeline(m_vol.m_ppline);
+	cmdb->bindResourceGroup(m_vol.m_rc, 0, nullptr);
+	m_r->drawQuad(cmdb);
+}
+
 Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount) const
 {
 	// Get some stuff

+ 2 - 2
src/anki/renderer/Fs.h

@@ -34,7 +34,7 @@ anki_internal:
 
 	void setPostRunBarriers(RenderingContext& ctx);
 
-	void drawVolumetric(CommandBufferPtr cmdb);
+	void drawVolumetric(RenderingContext& ctx, CommandBufferPtr cmdb);
 
 	TexturePtr getRt() const
 	{
@@ -65,7 +65,7 @@ private:
 	PipelineInitInfo m_state;
 	GrObjectCache* m_pplineCache = nullptr;
 
-	class
+	class Vol
 	{
 	public:
 		ShaderResourcePtr m_frag;

+ 1 - 6
src/anki/renderer/FsUpscale.cpp

@@ -35,12 +35,7 @@ Error FsUpscale::init(const ConfigSet& config)
 
 	rcInit.m_textures[2].m_texture = m_r->getFs().getRt();
 
-	rcInit.m_textures[3].m_texture = m_r->getVolumetric().m_rt;
-
-	rcInit.m_textures[4].m_texture = m_r->getSsao().getRt();
-
-	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
-	rcInit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
+	rcInit.m_textures[3].m_texture = m_r->getSsao().getRt();
 
 	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 

+ 8 - 5
src/anki/renderer/Renderer.cpp

@@ -149,12 +149,12 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_depth.reset(m_alloc.newInstance<DepthDownscale>(this));
 	ANKI_CHECK(m_depth->init(config));
 
-	m_fs.reset(m_alloc.newInstance<Fs>(this));
-	ANKI_CHECK(m_fs->init(config));
-
 	m_vol.reset(m_alloc.newInstance<Volumetric>(this));
 	ANKI_CHECK(m_vol->init(config));
 
+	m_fs.reset(m_alloc.newInstance<Fs>(this));
+	ANKI_CHECK(m_fs->init(config));
+
 	m_lf.reset(m_alloc.newInstance<Lf>(this));
 	ANKI_CHECK(m_lf->init(config));
 
@@ -245,16 +245,17 @@ Error Renderer::render(RenderingContext& ctx)
 
 	m_depth->m_qd.setPostRunBarriers(ctx);
 
+	m_vol->run(ctx);
+	m_vol->setPostRunBarriers(ctx);
+
 	m_lf->updateIndirectInfo(ctx, cmdb);
 
 	// Batch FS & SSAO & VOL
 	m_fs->run(ctx);
 	m_ssao->run(ctx);
-	m_vol->run(ctx);
 
 	m_ssao->setPostRunBarriers(ctx);
 	m_fs->setPostRunBarriers(ctx);
-	m_vol->setPostRunBarriers(ctx);
 
 	m_fsUpscale->run(ctx);
 
@@ -416,6 +417,7 @@ Error Renderer::buildCommandBuffersInternal(RenderingContext& ctx, U32 threadId,
 	if(ctx.m_fs.m_lastThreadWithWork == threadId)
 	{
 		m_lf->run(ctx, ctx.m_fs.m_commandBuffers[threadId]);
+		m_fs->drawVolumetric(ctx, ctx.m_fs.m_commandBuffers[threadId]);
 	}
 	else if(threadId == threadCount - 1 && ctx.m_fs.m_lastThreadWithWork == MAX_U32)
 	{
@@ -430,6 +432,7 @@ Error Renderer::buildCommandBuffersInternal(RenderingContext& ctx, U32 threadId,
 		cmdb->setPolygonOffset(0.0, 0.0);
 
 		m_lf->run(ctx, cmdb);
+		m_fs->drawVolumetric(ctx, cmdb);
 
 		ctx.m_fs.m_commandBuffers[threadId] = cmdb;
 	}

+ 1 - 1
src/anki/renderer/Volumetric.cpp

@@ -78,7 +78,7 @@ Error Volumetric::init(const ConfigSet& config)
 	FramebufferInitInfo fbInit;
 	fbInit.m_colorAttachmentCount = 1;
 	fbInit.m_colorAttachments[0].m_texture = m_rt;
-	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
+	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::LOAD;
 	fbInit.m_colorAttachments[0].m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE;
 	m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
 

+ 34 - 16
src/anki/util/Atomic.h

@@ -80,31 +80,49 @@ public:
 #endif
 	}
 
-	/// Fetch and add.
-	template<typename Y>
-	Value fetchAdd(const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	/// Fetch and add. Pointer specialization
+	template<typename Y, typename Q = T>
+	typename std::enable_if<std::is_pointer<Q>::value, Q>::type fetchAdd(
+		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
 #if defined(__GNUC__)
-		// Do a trick to workaround the fact that __atomic_fetch_add doesn't take into account the size of the type
-		// if that type is a pointer.
-		Value v = Value(0);
-		v += a;
-		return __atomic_fetch_add(&m_val, v, static_cast<int>(memOrd));
+		return __atomic_fetch_add(&m_val, a * sizeof(typename std::remove_pointer<Q>::type), static_cast<int>(memOrd));
 #else
 #error "TODO"
 #endif
 	}
 
-	/// Fetch and subtract.
-	template<typename Y>
-	Value fetchSub(const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	/// Fetch and add. Arithmetic specialization.
+	template<typename Y, typename Q = T>
+	typename std::enable_if<!std::is_pointer<Q>::value, Q>::type fetchAdd(
+		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
 #if defined(__GNUC__)
-		// Do a trick to workaround the fact that __atomic_fetch_add doesn't take into account the size of the type
-		// if that type is a pointer.
-		Value v = Value(0);
-		v += a;
-		return __atomic_fetch_sub(&m_val, v, static_cast<int>(memOrd));
+		return __atomic_fetch_add(&m_val, a, static_cast<int>(memOrd));
+#else
+#error "TODO"
+#endif
+	}
+
+	/// Fetch and subtract. Pointer specialization.
+	template<typename Y, typename Q = T>
+	typename std::enable_if<std::is_pointer<Q>::value, Q>::type fetchSub(
+		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	{
+#if defined(__GNUC__)
+		return __atomic_fetch_sub(&m_val, a * sizeof(typename std::remove_pointer<Q>::type), static_cast<int>(memOrd));
+#else
+#error "TODO"
+#endif
+	}
+
+	/// Fetch and subtract. Arithmetic specialization.
+	template<typename Y, typename Q = T>
+	typename std::enable_if<!std::is_pointer<Q>::value, Q>::type fetchSub(
+		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	{
+#if defined(__GNUC__)
+		return __atomic_fetch_sub(&m_val, a, static_cast<int>(memOrd));
 #else
 #error "TODO"
 #endif

+ 8 - 0
tests/util/Atomic.cpp

@@ -51,4 +51,12 @@ ANKI_TEST(Util, Atomic)
 		a.fetchSub(1);
 		ANKI_TEST_EXPECT_EQ(a.load(), &u[0]);
 	}
+
+	// Pointer of pointer
+	{
+		U32* pu = reinterpret_cast<U32*>(0xFFFAA);
+		Atomic<U32**> a{&pu};
+		a.fetchAdd(1);
+		ANKI_TEST_EXPECT_EQ(a.load(), &pu + 1);
+	}
 }