Browse Source

Adding SMAA

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
ae2d86f52a

+ 1 - 1
CMakeLists.txt

@@ -332,7 +332,7 @@ INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/anki/Config.h" DESTINATION "${INCLUDE
 
 
 # Include & lib directories
 # Include & lib directories
 include_directories("src" "thirdparty/tinyxml2/include" "thirdparty/lua" "thirdparty/z"
 include_directories("src" "thirdparty/tinyxml2/include" "thirdparty/lua" "thirdparty/z"
-	"${SDL2_INSTALL_DIR}/include/SDL2/" "${FREETYPE_INSTALL_DIR}/include/freetype2/" "thirdparty/newton/newton" "${CMAKE_CURRENT_BINARY_DIR}" ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glslang)
+	"${SDL2_INSTALL_DIR}/include/SDL2/" "${FREETYPE_INSTALL_DIR}/include/freetype2/" "thirdparty/newton/newton" "${CMAKE_CURRENT_BINARY_DIR}" ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glslang thirdparty)
 
 
 if(LINUX OR MACOS OR WINDOWS)
 if(LINUX OR MACOS OR WINDOWS)
 	include_directories("thirdparty/GLEW/include")
 	include_directories("thirdparty/GLEW/include")

+ 18 - 2
shaders/Pps.frag.glsl

@@ -7,11 +7,21 @@
 #include "shaders/Tonemapping.glsl"
 #include "shaders/Tonemapping.glsl"
 #include "shaders/Functions.glsl"
 #include "shaders/Functions.glsl"
 
 
+#if SMAA_ENABLED
+#define SMAA_GLSL_4
+#define SMAA_INCLUDE_PS 1
+#define SMAA_INCLUDE_VS 0
+#include "shaders/SMAA.hlsl"
+#endif
+
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_isRt;
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_isRt;
 layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_ppsBloomLfRt;
 layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_ppsBloomLfRt;
 layout(ANKI_TEX_BINDING(0, 2)) uniform sampler3D u_lut;
 layout(ANKI_TEX_BINDING(0, 2)) uniform sampler3D u_lut;
+#if SMAA_ENABLED
+layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_smaaBlendTex;
+#endif
 #if DBG_ENABLED
 #if DBG_ENABLED
-layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_dbgRt;
+layout(ANKI_TEX_BINDING(0, 4)) uniform sampler2D u_dbgRt;
 #endif
 #endif
 
 
 struct Luminance
 struct Luminance
@@ -25,6 +35,10 @@ layout(std140, ANKI_SS_BINDING(0, 0)) readonly buffer s0_
 };
 };
 
 
 layout(location = 0) in vec2 in_uv;
 layout(location = 0) in vec2 in_uv;
+#if SMAA_ENABLED
+layout(location = 1) in vec4 in_smaaOffset;
+#endif
+
 layout(location = 0) out vec3 out_color;
 layout(location = 0) out vec3 out_color;
 
 
 const vec2 TEX_OFFSET = vec2(1.0 / float(FBO_WIDTH), 1.0 / float(FBO_HEIGHT));
 const vec2 TEX_OFFSET = vec2(1.0 / float(FBO_WIDTH), 1.0 / float(FBO_HEIGHT));
@@ -112,6 +126,8 @@ void main()
 
 
 #if SHARPEN_ENABLED
 #if SHARPEN_ENABLED
 	out_color = sharpen(u_isRt, uv);
 	out_color = sharpen(u_isRt, uv);
+#elif SMAA_ENABLED
+	out_color = SMAANeighborhoodBlendingPS(uv, in_smaaOffset, u_isRt, u_smaaBlendTex).rgb;
 #else
 #else
 	out_color = textureLod(u_isRt, uv, 0.0).rgb;
 	out_color = textureLod(u_isRt, uv, 0.0).rgb;
 #endif
 #endif
@@ -131,7 +147,7 @@ void main()
 
 
 #if 0
 #if 0
 	{
 	{
-		out_color = bloom;
+		out_color = textureLod(u_isRt, uv, 0.0).rrr;
 	}
 	}
 #endif
 #endif
 }
 }

+ 32 - 0
shaders/Pps.vert.glsl

@@ -0,0 +1,32 @@
+// 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/Common.glsl"
+
+#if SMAA_ENABLED
+#define SMAA_GLSL_4
+#define SMAA_INCLUDE_PS 0
+#define SMAA_INCLUDE_VS 1
+#include "shaders/SMAA.hlsl"
+#endif
+
+layout(location = 0) out vec2 out_uv;
+#if SMAA_ENABLED
+layout(location = 1) out vec4 out_smaaOffset;
+#endif
+
+void main(void)
+{
+	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
+	vec2 pos = POSITIONS[gl_VertexID];
+	out_uv = pos * 0.5 + 0.5;
+
+	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
+
+#if SMAA_ENABLED
+	out_smaaOffset = vec4(0.0);
+	SMAANeighborhoodBlendingVS(out_uv, out_smaaOffset);
+#endif
+}

+ 28 - 0
shaders/SmaaEdge.frag.glsl

@@ -0,0 +1,28 @@
+// 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/Common.glsl"
+#define SMAA_GLSL_4
+#define SMAA_INCLUDE_PS 1
+#define SMAA_INCLUDE_VS 0
+#include "shaders/SMAA.hlsl"
+
+layout(location = 0) out vec2 out_color;
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_isRt;
+
+layout(location = 0) in vec2 in_uv;
+layout(location = 1) in vec4 in_offset0;
+layout(location = 2) in vec4 in_offset1;
+layout(location = 3) in vec4 in_offset2;
+
+void main()
+{
+	vec4 offsets[3];
+	offsets[0] = in_offset0;
+	offsets[1] = in_offset1;
+	offsets[2] = in_offset2;
+	out_color = SMAAColorEdgeDetectionPS(in_uv, offsets, u_isRt);
+}

+ 34 - 0
shaders/SmaaEdge.vert.glsl

@@ -0,0 +1,34 @@
+// 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/Common.glsl"
+
+#define SMAA_GLSL_4
+#define SMAA_INCLUDE_PS 0
+#define SMAA_INCLUDE_VS 1
+#include "shaders/SMAA.hlsl"
+
+layout(location = 0) out vec2 out_uv;
+layout(location = 1) out vec4 out_offset0;
+layout(location = 2) out vec4 out_offset1;
+layout(location = 3) out vec4 out_offset2;
+
+void main()
+{
+	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
+	vec2 pos = POSITIONS[gl_VertexID];
+	out_uv = pos * 0.5 + 0.5;
+
+	vec4 offsets[3];
+	offsets[0] = vec4(0.0);
+	offsets[1] = vec4(0.0);
+	offsets[2] = vec4(0.0);
+	SMAAEdgeDetectionVS(out_uv, offsets);
+	out_offset0 = offsets[0];
+	out_offset1 = offsets[1];
+	out_offset2 = offsets[2];
+
+	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
+}

+ 33 - 0
shaders/SmaaWeights.frag.glsl

@@ -0,0 +1,33 @@
+// 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/Common.glsl"
+
+#define SMAA_GLSL_4
+#define SMAA_INCLUDE_PS 1
+#define SMAA_INCLUDE_VS 0
+#include "shaders/SMAA.hlsl"
+
+layout(location = 0) out vec4 out_color;
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_edgesTex;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_areaTex;
+layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_searchTex;
+
+layout(location = 0) in vec2 in_uv;
+layout(location = 1) in vec2 in_pixcoord;
+layout(location = 2) in vec4 in_offset0;
+layout(location = 3) in vec4 in_offset1;
+layout(location = 4) in vec4 in_offset2;
+
+void main()
+{
+	vec4 offsets[3];
+	offsets[0] = in_offset0;
+	offsets[1] = in_offset1;
+	offsets[2] = in_offset2;
+	out_color =
+		SMAABlendingWeightCalculationPS(in_uv, in_pixcoord, offsets, u_edgesTex, u_areaTex, u_searchTex, vec4(0.0));
+}

+ 36 - 0
shaders/SmaaWeights.vert.glsl

@@ -0,0 +1,36 @@
+// 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/Common.glsl"
+
+#define SMAA_GLSL_4
+#define SMAA_INCLUDE_PS 0
+#define SMAA_INCLUDE_VS 1
+#include "shaders/SMAA.hlsl"
+
+layout(location = 0) out vec2 out_uv;
+layout(location = 1) out vec2 out_pixcoord;
+layout(location = 2) out vec4 out_offset0;
+layout(location = 3) out vec4 out_offset1;
+layout(location = 4) out vec4 out_offset2;
+
+void main(void)
+{
+	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
+	vec2 pos = POSITIONS[gl_VertexID];
+	out_uv = pos * 0.5 + 0.5;
+
+	vec4 offsets[3];
+	offsets[0] = vec4(0.0);
+	offsets[1] = vec4(0.0);
+	offsets[2] = vec4(0.0);
+	out_pixcoord = vec2(0.0);
+	SMAABlendingWeightCalculationVS(out_uv, out_pixcoord, offsets);
+	out_offset0 = offsets[0];
+	out_offset1 = offsets[1];
+	out_offset2 = offsets[2];
+
+	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
+}

+ 16 - 1
src/anki/gr/gl/TextureImpl.cpp

@@ -76,7 +76,7 @@ static void convertTextureInformation(
 		break;
 		break;
 #endif
 #endif
 	case ComponentFormat::R8:
 	case ComponentFormat::R8:
-		format = GL_R;
+		format = GL_RED;
 
 
 		if(pf.m_transform == TransformFormat::UNORM)
 		if(pf.m_transform == TransformFormat::UNORM)
 		{
 		{
@@ -90,6 +90,21 @@ static void convertTextureInformation(
 			type = GL_BYTE;
 			type = GL_BYTE;
 		}
 		}
 		break;
 		break;
+	case ComponentFormat::R8G8:
+		format = GL_RG;
+
+		if(pf.m_transform == TransformFormat::UNORM)
+		{
+			internalFormat = GL_RG8;
+			type = GL_UNSIGNED_BYTE;
+		}
+		else
+		{
+			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
+			internalFormat = GL_RG8_SNORM;
+			type = GL_BYTE;
+		}
+		break;
 	case ComponentFormat::R8G8B8:
 	case ComponentFormat::R8G8B8:
 		format = GL_RGB;
 		format = GL_RGB;
 
 

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

@@ -30,6 +30,7 @@ class Upsample;
 class DownscaleBlur;
 class DownscaleBlur;
 class Volumetric;
 class Volumetric;
 class HalfDepth;
 class HalfDepth;
+class Smaa;
 
 
 class RenderingContext;
 class RenderingContext;
 class DebugDrawer;
 class DebugDrawer;

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

@@ -145,8 +145,8 @@ Error Lf::initOcclusion(const ConfigSet& config)
 	init.m_color.m_attachments[1].m_channelWriteMask = ColorBit::NONE;
 	init.m_color.m_attachments[1].m_channelWriteMask = ColorBit::NONE;
 	init.m_color.m_attachments[2].m_format = MS_COLOR_ATTACHMENT_PIXEL_FORMATS[2];
 	init.m_color.m_attachments[2].m_format = MS_COLOR_ATTACHMENT_PIXEL_FORMATS[2];
 	init.m_color.m_attachments[2].m_channelWriteMask = ColorBit::NONE;
 	init.m_color.m_attachments[2].m_channelWriteMask = ColorBit::NONE;
-	init.m_shaders[U(ShaderType::VERTEX)] = m_occlusionVert->getGrShader();
-	init.m_shaders[U(ShaderType::FRAGMENT)] = m_occlusionFrag->getGrShader();
+	init.m_shaders[ShaderType::VERTEX] = m_occlusionVert->getGrShader();
+	init.m_shaders[ShaderType::FRAGMENT] = m_occlusionFrag->getGrShader();
 	m_occlusionPpline = gr.newInstance<Pipeline>(init);
 	m_occlusionPpline = gr.newInstance<Pipeline>(init);
 
 
 	rcinit = ResourceGroupInitInfo();
 	rcinit = ResourceGroupInitInfo();

+ 45 - 12
src/anki/renderer/Pps.cpp

@@ -11,6 +11,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/Smaa.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Logger.h>
 #include <anki/misc/ConfigSet.h>
 #include <anki/misc/ConfigSet.h>
 #include <anki/scene/SceneNode.h>
 #include <anki/scene/SceneNode.h>
@@ -107,29 +108,60 @@ Error Pps::run(RenderingContext& ctx)
 						"#define FBO_HEIGHT %u\n"
 						"#define FBO_HEIGHT %u\n"
 						"#define LUT_SIZE %u.0\n"
 						"#define LUT_SIZE %u.0\n"
 						"#define DBG_ENABLED %u\n"
 						"#define DBG_ENABLED %u\n"
-						"#define DRAW_TO_DEFAULT %u\n",
+						"#define DRAW_TO_DEFAULT %u\n"
+						"#define SMAA_ENABLED 1\n"
+						"#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
+						"#define SMAA_PRESET_%s\n",
 				true,
 				true,
 				m_sharpenEnabled,
 				m_sharpenEnabled,
 				m_r->getWidth(),
 				m_r->getWidth(),
 				m_r->getHeight(),
 				m_r->getHeight(),
 				LUT_SIZE,
 				LUT_SIZE,
 				dbgEnabled,
 				dbgEnabled,
-				drawToDefaultFb);
+				drawToDefaultFb,
+				1.0 / m_r->getWidth(),
+				1.0 / m_r->getHeight(),
+				F32(m_r->getWidth()),
+				F32(m_r->getHeight()),
+				&m_r->getSmaa().m_qualityPerset[0]);
 
 
 			ANKI_CHECK(getResourceManager().loadResourceToCache(frag, "shaders/Pps.frag.glsl", pps.toCString(), "r_"));
 			ANKI_CHECK(getResourceManager().loadResourceToCache(frag, "shaders/Pps.frag.glsl", pps.toCString(), "r_"));
 		}
 		}
 
 
-		ColorStateInfo colorState;
-		colorState.m_attachmentCount = 1;
-		if(drawToDefaultFb)
+		if(!m_vert)
 		{
 		{
-			colorState.m_attachments[0].m_format.m_components = ComponentFormat::DEFAULT_FRAMEBUFFER;
-		}
-		else
-		{
-			colorState.m_attachments[0].m_format = RT_PIXEL_FORMAT;
+			StringAuto pps(ctx.m_tempAllocator);
+
+			pps.sprintf("#define SMAA_ENABLED 1\n"
+						"#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
+						"#define SMAA_PRESET_%s\n",
+				1.0 / m_r->getWidth(),
+				1.0 / m_r->getHeight(),
+				F32(m_r->getWidth()),
+				F32(m_r->getHeight()),
+				&m_r->getSmaa().m_qualityPerset[0]);
+
+			ANKI_CHECK(
+				getResourceManager().loadResourceToCache(m_vert, "shaders/Pps.vert.glsl", pps.toCString(), "r_"));
 		}
 		}
-		m_r->createDrawQuadPipeline(frag->getGrShader(), colorState, ppline);
+
+		PixelFormat pfs = (drawToDefaultFb) ? PixelFormat(ComponentFormat::DEFAULT_FRAMEBUFFER, TransformFormat::NONE)
+											: RT_PIXEL_FORMAT;
+
+		PipelineInitInfo ppinit;
+
+		ppinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+
+		ppinit.m_depthStencil.m_depthWriteEnabled = false;
+		ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+
+		ppinit.m_color.m_attachmentCount = 1;
+		ppinit.m_color.m_attachments[0].m_format = pfs;
+
+		ppinit.m_shaders[ShaderType::VERTEX] = m_vert->getGrShader();
+		ppinit.m_shaders[ShaderType::FRAGMENT] = frag->getGrShader();
+
+		ppline = m_r->getGrManager().newInstance<Pipeline>(ppinit);
 	}
 	}
 
 
 	// Get or create the resource group
 	// Get or create the resource group
@@ -140,9 +172,10 @@ Error Pps::run(RenderingContext& ctx)
 		rcInit.m_textures[0].m_texture = m_r->getIs().getRt();
 		rcInit.m_textures[0].m_texture = m_r->getIs().getRt();
 		rcInit.m_textures[1].m_texture = m_r->getBloom().getFinalRt();
 		rcInit.m_textures[1].m_texture = m_r->getBloom().getFinalRt();
 		rcInit.m_textures[2].m_texture = m_lut->getGrTexture();
 		rcInit.m_textures[2].m_texture = m_lut->getGrTexture();
+		rcInit.m_textures[3].m_texture = m_r->getSmaa().m_weights.m_rt;
 		if(dbgEnabled)
 		if(dbgEnabled)
 		{
 		{
-			rcInit.m_textures[3].m_texture = m_r->getDbg().getRt();
+			rcInit.m_textures[4].m_texture = m_r->getDbg().getRt();
 		}
 		}
 
 
 		rcInit.m_storageBuffers[0].m_buffer = m_r->getTm().getAverageLuminanceBuffer();
 		rcInit.m_storageBuffers[0].m_buffer = m_r->getTm().getAverageLuminanceBuffer();

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

@@ -45,6 +45,7 @@ private:
 
 
 	FramebufferPtr m_fb;
 	FramebufferPtr m_fb;
 	Array2d<ShaderResourcePtr, 2, 2> m_frag; ///< One with Dbg and one without
 	Array2d<ShaderResourcePtr, 2, 2> m_frag; ///< One with Dbg and one without
+	ShaderResourcePtr m_vert;
 	Array2d<PipelinePtr, 2, 2> m_ppline; ///< With Dbg, Default FB or not
 	Array2d<PipelinePtr, 2, 2> m_ppline; ///< With Dbg, Default FB or not
 	TexturePtr m_rt;
 	TexturePtr m_rt;
 	Array<ResourceGroupPtr, 2> m_rcGroup; ///< One with Dbg and one without
 	Array<ResourceGroupPtr, 2> m_rcGroup; ///< One with Dbg and one without

+ 18 - 2
src/anki/renderer/Renderer.cpp

@@ -26,6 +26,7 @@
 #include <anki/renderer/DownscaleBlur.h>
 #include <anki/renderer/DownscaleBlur.h>
 #include <anki/renderer/Volumetric.h>
 #include <anki/renderer/Volumetric.h>
 #include <anki/renderer/HalfDepth.h>
 #include <anki/renderer/HalfDepth.h>
+#include <anki/renderer/Smaa.h>
 
 
 namespace anki
 namespace anki
 {
 {
@@ -168,6 +169,9 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_downscale.reset(getAllocator().newInstance<DownscaleBlur>(this));
 	m_downscale.reset(getAllocator().newInstance<DownscaleBlur>(this));
 	ANKI_CHECK(m_downscale->init(config));
 	ANKI_CHECK(m_downscale->init(config));
 
 
+	m_smaa.reset(getAllocator().newInstance<Smaa>(this));
+	ANKI_CHECK(m_smaa->init(config));
+
 	m_bloom.reset(m_alloc.newInstance<Bloom>(this));
 	m_bloom.reset(m_alloc.newInstance<Bloom>(this));
 	ANKI_CHECK(m_bloom->init(config));
 	ANKI_CHECK(m_bloom->init(config));
 
 
@@ -240,6 +244,9 @@ Error Renderer::render(RenderingContext& ctx)
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureSurfaceInfo(0, 0, 0, 0));
 		TextureSurfaceInfo(0, 0, 0, 0));
 
 
+	m_smaa->m_edge.setPreRunBarriers(ctx);
+	m_smaa->m_weights.setPreRunBarriers(ctx);
+
 	// SM
 	// SM
 	m_sm->run(ctx);
 	m_sm->run(ctx);
 
 
@@ -280,17 +287,26 @@ Error Renderer::render(RenderingContext& ctx)
 		TextureUsageBit::SAMPLED_COMPUTE,
 		TextureUsageBit::SAMPLED_COMPUTE,
 		TextureSurfaceInfo(m_is->getRtMipmapCount() - 1, 0, 0, 0));
 		TextureSurfaceInfo(m_is->getRtMipmapCount() - 1, 0, 0, 0));
 
 
+	// Batch TM + SMAA_pass0
 	m_tm->run(ctx);
 	m_tm->run(ctx);
+	m_smaa->m_edge.run(ctx);
 
 
+	// Barriers
 	cmdb->setTextureSurfaceBarrier(m_is->getRt(),
 	cmdb->setTextureSurfaceBarrier(m_is->getRt(),
 		TextureUsageBit::SAMPLED_COMPUTE,
 		TextureUsageBit::SAMPLED_COMPUTE,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureSurfaceInfo(m_is->getRtMipmapCount() - 1, 0, 0, 0));
 		TextureSurfaceInfo(m_is->getRtMipmapCount() - 1, 0, 0, 0));
+	m_smaa->m_edge.setPostRunBarriers(ctx);
 
 
+	// Batch bloom + SSLF + SMAA_pass1
 	m_bloom->run(ctx);
 	m_bloom->run(ctx);
 	m_sslf->run(ctx);
 	m_sslf->run(ctx);
 	cmdb->endRenderPass();
 	cmdb->endRenderPass();
+	m_smaa->m_weights.run(ctx);
+
+	// Barriers
 	m_bloom->setPostRunBarriers(ctx);
 	m_bloom->setPostRunBarriers(ctx);
+	m_smaa->m_weights.setPostRunBarriers(ctx);
 
 
 	if(m_dbg->getEnabled())
 	if(m_dbg->getEnabled())
 	{
 	{
@@ -369,8 +385,8 @@ void Renderer::createDrawQuadPipeline(ShaderPtr frag, const ColorStateInfo& colo
 
 
 	init.m_color = colorState;
 	init.m_color = colorState;
 
 
-	init.m_shaders[U(ShaderType::VERTEX)] = m_drawQuadVert->getGrShader();
-	init.m_shaders[U(ShaderType::FRAGMENT)] = frag;
+	init.m_shaders[ShaderType::VERTEX] = m_drawQuadVert->getGrShader();
+	init.m_shaders[ShaderType::FRAGMENT] = frag;
 	ppline = m_gr->newInstance<Pipeline>(init);
 	ppline = m_gr->newInstance<Pipeline>(init);
 }
 }
 
 

+ 6 - 0
src/anki/renderer/Renderer.h

@@ -199,6 +199,11 @@ public:
 		return *m_dbg;
 		return *m_dbg;
 	}
 	}
 
 
+	Smaa& getSmaa()
+	{
+		return *m_smaa;
+	}
+
 	U32 getWidth() const
 	U32 getWidth() const
 	{
 	{
 		return m_width;
 		return m_width;
@@ -379,6 +384,7 @@ private:
 	UniquePtr<Lf> m_lf; ///< Forward shading lens flares.
 	UniquePtr<Lf> m_lf; ///< Forward shading lens flares.
 	UniquePtr<Upsample> m_upsample;
 	UniquePtr<Upsample> m_upsample;
 	UniquePtr<DownscaleBlur> m_downscale;
 	UniquePtr<DownscaleBlur> m_downscale;
+	UniquePtr<Smaa> m_smaa;
 	UniquePtr<Tm> m_tm;
 	UniquePtr<Tm> m_tm;
 	UniquePtr<Ssao> m_ssao;
 	UniquePtr<Ssao> m_ssao;
 	UniquePtr<Bloom> m_bloom;
 	UniquePtr<Bloom> m_bloom;

+ 257 - 0
src/anki/renderer/Smaa.cpp

@@ -0,0 +1,257 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/renderer/Smaa.h>
+#include <anki/renderer/Renderer.h>
+#include <anki/renderer/Is.h>
+#include <SMAA/AreaTex.h>
+#include <SMAA/SearchTex.h>
+
+namespace anki
+{
+
+static const PixelFormat EDGE_PIXEL_FORMAT(ComponentFormat::R8G8, TransformFormat::UNORM);
+static const PixelFormat WEIGHTS_PIXEL_FORMAT(ComponentFormat::R8G8B8A8, TransformFormat::UNORM);
+
+SmaaEdge::~SmaaEdge()
+{
+}
+
+Error SmaaEdge::init(const ConfigSet& initializer)
+{
+	GrManager& gr = getGrManager();
+
+	// Create shaders
+	StringAuto pps(getAllocator());
+	pps.sprintf("#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
+				"#define SMAA_PRESET_%s\n",
+		1.0 / m_r->getWidth(),
+		1.0 / m_r->getHeight(),
+		F32(m_r->getWidth()),
+		F32(m_r->getHeight()),
+		&m_r->getSmaa().m_qualityPerset[0]);
+
+	ANKI_CHECK(getResourceManager().loadResourceToCache(m_vert, "shaders/SmaaEdge.vert.glsl", pps.toCString(), "r_"));
+	ANKI_CHECK(getResourceManager().loadResourceToCache(m_frag, "shaders/SmaaEdge.frag.glsl", pps.toCString(), "r_"));
+
+	// Create ppline
+	PipelineInitInfo ppinit;
+
+	ppinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+
+	ppinit.m_depthStencil.m_depthWriteEnabled = false;
+	ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+
+	ppinit.m_color.m_attachmentCount = 1;
+	ppinit.m_color.m_attachments[0].m_format = EDGE_PIXEL_FORMAT;
+
+	ppinit.m_shaders[ShaderType::VERTEX] = m_vert->getGrShader();
+	ppinit.m_shaders[ShaderType::FRAGMENT] = m_frag->getGrShader();
+
+	m_ppline = gr.newInstance<Pipeline>(ppinit);
+
+	// Create RT
+	m_r->createRenderTarget(m_r->getWidth(),
+		m_r->getHeight(),
+		EDGE_PIXEL_FORMAT,
+		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		SamplingFilter::LINEAR,
+		1,
+		m_rt);
+
+	// Create FB
+	FramebufferInitInfo fbInit;
+	fbInit.m_colorAttachmentCount = 1;
+	fbInit.m_colorAttachments[0].m_texture = m_rt;
+	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::CLEAR;
+	fbInit.m_colorAttachments[0].m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE;
+	m_fb = gr.newInstance<Framebuffer>(fbInit);
+
+	// Create RC group
+	ResourceGroupInitInfo rcinit;
+	rcinit.m_textures[0].m_texture = m_r->getIs().getRt();
+	m_rcgroup = gr.newInstance<ResourceGroup>(rcinit);
+
+	return ErrorCode::NONE;
+}
+
+void SmaaEdge::setPreRunBarriers(RenderingContext& ctx)
+{
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(
+		m_rt, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, TextureSurfaceInfo(0, 0, 0, 0));
+}
+
+void SmaaEdge::setPostRunBarriers(RenderingContext& ctx)
+{
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt,
+		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		TextureUsageBit::SAMPLED_FRAGMENT,
+		TextureSurfaceInfo(0, 0, 0, 0));
+}
+
+void SmaaEdge::run(RenderingContext& ctx)
+{
+	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
+
+	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
+	cmdb->bindResourceGroup(m_rcgroup, 0, nullptr);
+	cmdb->bindPipeline(m_ppline);
+	cmdb->beginRenderPass(m_fb);
+
+	cmdb->drawArrays(3);
+
+	cmdb->endRenderPass();
+}
+
+SmaaWeights::~SmaaWeights()
+{
+}
+
+Error SmaaWeights::init(const ConfigSet& initializer)
+{
+	GrManager& gr = getGrManager();
+
+	// Create shaders
+	StringAuto pps(getAllocator());
+	pps.sprintf("#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
+				"#define SMAA_PRESET_%s\n",
+		1.0 / m_r->getWidth(),
+		1.0 / m_r->getHeight(),
+		F32(m_r->getWidth()),
+		F32(m_r->getHeight()),
+		&m_r->getSmaa().m_qualityPerset[0]);
+
+	ANKI_CHECK(
+		getResourceManager().loadResourceToCache(m_vert, "shaders/SmaaWeights.vert.glsl", pps.toCString(), "r_"));
+	ANKI_CHECK(
+		getResourceManager().loadResourceToCache(m_frag, "shaders/SmaaWeights.frag.glsl", pps.toCString(), "r_"));
+
+	// Create ppline
+	PipelineInitInfo ppinit;
+
+	ppinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+
+	ppinit.m_depthStencil.m_depthWriteEnabled = false;
+	ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+
+	ppinit.m_color.m_attachmentCount = 1;
+	ppinit.m_color.m_attachments[0].m_format = WEIGHTS_PIXEL_FORMAT;
+
+	ppinit.m_shaders[ShaderType::VERTEX] = m_vert->getGrShader();
+	ppinit.m_shaders[ShaderType::FRAGMENT] = m_frag->getGrShader();
+
+	m_ppline = gr.newInstance<Pipeline>(ppinit);
+
+	// Create RT
+	m_r->createRenderTarget(m_r->getWidth(),
+		m_r->getHeight(),
+		WEIGHTS_PIXEL_FORMAT,
+		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		SamplingFilter::LINEAR,
+		1,
+		m_rt);
+
+	// Create FB
+	FramebufferInitInfo fbInit;
+	fbInit.m_colorAttachmentCount = 1;
+	fbInit.m_colorAttachments[0].m_texture = m_rt;
+	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::CLEAR;
+	fbInit.m_colorAttachments[0].m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE;
+	m_fb = gr.newInstance<Framebuffer>(fbInit);
+
+	// Create Area texture
+	CommandBufferInitInfo cmdbinit;
+	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH;
+	CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cmdbinit);
+
+	{
+		TextureInitInfo texinit;
+		texinit.m_width = AREATEX_WIDTH;
+		texinit.m_height = AREATEX_HEIGHT;
+		texinit.m_format = PixelFormat(ComponentFormat::R8G8, TransformFormat::UNORM);
+		texinit.m_usage = TextureUsageBit::UPLOAD | TextureUsageBit::SAMPLED_FRAGMENT;
+		texinit.m_sampling.m_minMagFilter = SamplingFilter::LINEAR;
+		texinit.m_sampling.m_repeat = false;
+
+		m_areaTex = gr.newInstance<Texture>(texinit);
+
+		Array<U8, AREATEX_SIZE> tmpBuff;
+		for(U y = 0; y < AREATEX_HEIGHT; ++y)
+		{
+			U srcY = AREATEX_HEIGHT - 1 - y;
+			memcpy(&tmpBuff[y * AREATEX_PITCH], areaTexBytes + srcY * AREATEX_PITCH, AREATEX_PITCH);
+		}
+
+		const TextureSurfaceInfo surf(0, 0, 0, 0);
+		cmdb->setTextureSurfaceBarrier(m_areaTex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
+		cmdb->uploadTextureSurfaceCopyData(m_areaTex, surf, &tmpBuff[0], sizeof(tmpBuff));
+		cmdb->setTextureSurfaceBarrier(m_areaTex, TextureUsageBit::UPLOAD, TextureUsageBit::SAMPLED_FRAGMENT, surf);
+	}
+
+	// Create search texture
+	{
+		TextureInitInfo texinit;
+		texinit.m_width = SEARCHTEX_WIDTH;
+		texinit.m_height = SEARCHTEX_HEIGHT;
+		texinit.m_format = PixelFormat(ComponentFormat::R8, TransformFormat::UNORM);
+		texinit.m_usage = TextureUsageBit::UPLOAD | TextureUsageBit::SAMPLED_FRAGMENT;
+		texinit.m_sampling.m_minMagFilter = SamplingFilter::LINEAR;
+		texinit.m_sampling.m_repeat = false;
+
+		m_searchTex = gr.newInstance<Texture>(texinit);
+
+		Array<U8, SEARCHTEX_SIZE> tmpBuff;
+		for(U y = 0; y < SEARCHTEX_HEIGHT; ++y)
+		{
+			U srcY = SEARCHTEX_HEIGHT - 1 - y;
+			memcpy(&tmpBuff[y * SEARCHTEX_PITCH], searchTexBytes + srcY * SEARCHTEX_PITCH, SEARCHTEX_PITCH);
+		}
+
+		const TextureSurfaceInfo surf(0, 0, 0, 0);
+		cmdb->setTextureSurfaceBarrier(m_searchTex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
+		cmdb->uploadTextureSurfaceCopyData(m_searchTex, surf, &tmpBuff[0], sizeof(tmpBuff));
+		cmdb->setTextureSurfaceBarrier(m_searchTex, TextureUsageBit::UPLOAD, TextureUsageBit::SAMPLED_FRAGMENT, surf);
+	}
+	cmdb->flush();
+
+	// Create RC group
+	ResourceGroupInitInfo rcinit;
+	rcinit.m_textures[0].m_texture = m_r->getSmaa().m_edge.m_rt;
+	rcinit.m_textures[1].m_texture = m_areaTex;
+	rcinit.m_textures[2].m_texture = m_searchTex;
+	m_rcgroup = gr.newInstance<ResourceGroup>(rcinit);
+
+	return ErrorCode::NONE;
+}
+
+void SmaaWeights::setPreRunBarriers(RenderingContext& ctx)
+{
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(
+		m_rt, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, TextureSurfaceInfo(0, 0, 0, 0));
+}
+
+void SmaaWeights::setPostRunBarriers(RenderingContext& ctx)
+{
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt,
+		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		TextureUsageBit::SAMPLED_FRAGMENT,
+		TextureSurfaceInfo(0, 0, 0, 0));
+}
+
+void SmaaWeights::run(RenderingContext& ctx)
+{
+	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
+
+	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
+	cmdb->bindResourceGroup(m_rcgroup, 0, nullptr);
+	cmdb->bindPipeline(m_ppline);
+	cmdb->beginRenderPass(m_fb);
+
+	cmdb->drawArrays(3);
+
+	cmdb->endRenderPass();
+}
+
+} // end namespace anki

+ 98 - 0
src/anki/renderer/Smaa.h

@@ -0,0 +1,98 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/renderer/RenderingPass.h>
+
+namespace anki
+{
+
+/// @addtogroup renderer
+/// @{
+
+class SmaaEdge : public RenderingPass
+{
+anki_internal:
+	TexturePtr m_rt;
+
+	SmaaEdge(Renderer* r)
+		: RenderingPass(r)
+	{
+	}
+
+	~SmaaEdge();
+
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+
+	void setPreRunBarriers(RenderingContext& ctx);
+	void run(RenderingContext& ctx);
+	void setPostRunBarriers(RenderingContext& ctx);
+
+private:
+	FramebufferPtr m_fb;
+	ShaderResourcePtr m_vert;
+	ShaderResourcePtr m_frag;
+	PipelinePtr m_ppline;
+	ResourceGroupPtr m_rcgroup;
+};
+
+class SmaaWeights : public RenderingPass
+{
+anki_internal:
+	TexturePtr m_rt;
+
+	SmaaWeights(Renderer* r)
+		: RenderingPass(r)
+	{
+	}
+
+	~SmaaWeights();
+
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+
+	void setPreRunBarriers(RenderingContext& ctx);
+	void run(RenderingContext& ctx);
+	void setPostRunBarriers(RenderingContext& ctx);
+
+private:
+	FramebufferPtr m_fb;
+	ShaderResourcePtr m_vert;
+	ShaderResourcePtr m_frag;
+	PipelinePtr m_ppline;
+	TexturePtr m_areaTex;
+	TexturePtr m_searchTex;
+	ResourceGroupPtr m_rcgroup;
+};
+
+class Smaa : public RenderingPass
+{
+anki_internal:
+	SmaaEdge m_edge;
+	SmaaWeights m_weights;
+	CString m_qualityPerset;
+
+	Smaa(Renderer* r)
+		: RenderingPass(r)
+		, m_edge(r)
+		, m_weights(r)
+	{
+	}
+
+	~Smaa()
+	{
+	}
+
+	ANKI_USE_RESULT Error init(const ConfigSet& cfg)
+	{
+		m_qualityPerset = "ULTRA";
+		ANKI_CHECK(m_edge.init(cfg));
+		ANKI_CHECK(m_weights.init(cfg));
+		return ErrorCode::NONE;
+	}
+};
+/// @}
+
+} // end namespace anki

+ 1 - 1
thirdparty

@@ -1 +1 @@
-Subproject commit 02151a1c529bc76d28e23b0d6e471acfce1485d3
+Subproject commit a81042c3c6668ff207e1932b060a3057176d60c0