瀏覽代碼

Adding GL sampler support & optimizing renderer a bit & adding collision algorithms

Panagiotis Christopoulos Charitos 11 年之前
父節點
當前提交
ad49786c91

+ 26 - 0
include/anki/collision/Common.h

@@ -0,0 +1,26 @@
+#ifndef ANKI_COLLISION_COMMON_H
+#define ANKI_COLLISION_COMMON_H
+
+#include "anki/collision/Forward.h"
+#include "anki/util/Allocator.h"
+#include "anki/util/Vector.h"
+
+namespace anki {
+
+/// @addtogroup collision
+/// @{
+
+/// The type of the collision temporary allocator
+template<typename T>
+using CollisionTempAllocator = StackAllocator<T, false>;
+
+/// A temporary vector
+template<typename T>
+using CollisionTempVector = Vector<T, CollisionTempAllocator<T>>;
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 25 - 0
include/anki/collision/ContactPoint.h

@@ -0,0 +1,25 @@
+#ifndef ANKI_COLLISION_CONTACT_POINT_H
+#define ANKI_COLLISION_CONTACT_POINT_H
+
+#include "anki/Math.h"
+
+namespace anki {
+
+/// @addtogroup collision
+/// @{
+
+/// Collision test contact point
+class ContactPoint
+{
+public:
+	Vec3 m_position;
+	Vec3 m_normal;
+	F32 m_depth;
+};
+
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 2 - 0
include/anki/collision/Forward.h

@@ -14,6 +14,8 @@ class Sphere;
 class Aabb;
 class CompoundShape;
 
+class ContactPoint;
+
 } // end namespace anki
 
 #endif

+ 40 - 0
include/anki/collision/Tests.h

@@ -0,0 +1,40 @@
+#ifndef ANKI_COLLISION_TESTS_H
+#define ANKI_COLLISION_TESTS_H
+
+#include "anki/collision/Common.h"
+
+namespace anki {
+namespace detail {
+
+/// @addtogroup collision
+/// @{
+
+/// Provides the collision algorithms that detect collision between various
+/// shapes
+/// @code
+/// +------+------+------+------+------+------+------+
+/// |      | LS   | OBB  | P    | S    | AABB |      |
+/// +------+------+------+------+------+------+------+
+/// | LS   | N/A  | OK   | OK   | OK   | OK   |      |
+/// +------+------+------+------+------+------+------+
+/// | OBB  |      | OK   | OK   | OK   | OK   |      |
+/// +------+------+------+------+------+------+------+
+/// | P    |      |      | OK   | OK   | OK   |      |
+/// +------+------+------+------+------+------+------+
+/// | S    |      |      |      | OK   | OK   |      |
+/// +------+------+------+------+------+------+------+
+/// | AABB |      |      |      |      | OK   |      |
+/// +------+------+------+------+------+------+------+
+/// @endcode
+
+
+// 2nd line
+U test(const Obb& a, const Obb& b, CollisionTempVector<ContactPoint>& points);
+
+/// @}
+
+} // end namespace detail 
+} // end namespace anki
+
+#endif
+

+ 2 - 2
include/anki/gl/GlFramebuffer.h

@@ -64,8 +64,8 @@ public:
 	void bind(Bool invalidate);
 
 	/// Blit another framebuffer to this
-	void blit(const GlFramebuffer& fb, const Array<F32, 4>& sourceRect,
-		const Array<F32, 4>& destRect, Bool linear);
+	void blit(const GlFramebuffer& fb, const Array<U32, 4>& sourceRect,
+		const Array<U32, 4>& destRect, GLbitfield attachmentMask, Bool linear);
 
 private:
 	Array<GlTextureHandle, MAX_COLOR_ATTACHMENTS + 1> m_attachments;

+ 5 - 2
include/anki/gl/GlFramebufferHandle.h

@@ -41,11 +41,14 @@ public:
 	/// @param[in] b The sorce framebuffer
 	/// @param[in] sourceRect The source rectangle
 	/// @param[in] destRect The destination rectangle
+	/// @param attachmentMask The attachments to blit
 	/// @param linear Perform linean filtering
 	void blit(GlJobChainHandle& jobs,
 		const GlFramebufferHandle& b, 
-		const Array<F32, 4>& sourceRect,
-		const Array<F32, 4>& destRect, Bool linear);
+		const Array<U32, 4>& sourceRect,
+		const Array<U32, 4>& destRect, 
+		GLbitfield attachmentMask,
+		Bool linear);
 };
 
 } // end namespace anki

+ 2 - 0
include/anki/gl/GlJobManager.h

@@ -110,6 +110,8 @@ private:
 	GlJobChainHandle m_syncJobs;
 	GlClientSyncHandle m_sync;
 
+	String m_error;
+
 	/// The function that the thread runs
 	void threadLoop();
 	void prepare();

+ 67 - 0
include/anki/gl/GlTexture.h

@@ -157,6 +157,73 @@ private:
 	void setFilterNoBind(Filter filterType);
 };
 
+/// Sampler container
+class GlSampler: public GlObject
+{
+public:
+	typedef GlObject Base;
+	typedef GlTextureFilter Filter;
+
+	/// @name Constructors/Destructor
+	/// @{
+	GlSampler()
+	{
+		glGenSamplers(1, &m_glName);
+	}
+
+	GlSampler(GlSampler&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GlSampler()
+	{
+		destroy();
+	}
+	/// @}
+
+	/// Move
+	GlSampler& operator=(GlSampler&& b)
+	{
+		destroy();
+		Base::operator=(std::forward<Base>(b));
+		return *this;
+	}
+
+	/// Set filter type
+	void setFilter(const Filter filterType);
+
+	/// Set sampler parameter
+	void setParameter(GLenum param, GLint value)
+	{
+		ANKI_ASSERT(isCreated());
+		glSamplerParameteri(m_glName, param, value);
+	}
+
+	/// Bind the texture to a specified unit
+	void bind(U32 unit) const
+	{
+		ANKI_ASSERT(isCreated());
+		glBindSampler(unit, m_glName);
+	}
+
+	/// Unbind sampler from unit
+	static void unbind(U32 unit)
+	{
+		glBindSampler(unit, 0);
+	}
+
+private:
+	void destroy()
+	{
+		if(m_glName)
+		{
+			glDeleteSamplers(1, &m_glName);
+			m_glName = 0;
+		}
+	}
+};
+
 /// @}
 
 } // end namespace anki

+ 39 - 5
include/anki/gl/GlTextureHandle.h

@@ -8,6 +8,7 @@ namespace anki {
 
 // Forward
 class GlTexture;
+class GlSampler;
 
 /// @addtogroup opengl_containers
 /// @{
@@ -35,22 +36,22 @@ public:
 	GlTextureHandle();
 
 	/// Create the texture
-	explicit GlTextureHandle(GlJobChainHandle& chain, const Initializer& init);
+	explicit GlTextureHandle(GlJobChainHandle& jobs, const Initializer& init);
 
 	~GlTextureHandle();
 	/// @}
 
 	/// Bind to a unit
-	void bind(GlJobChainHandle& chain, U32 unit);
+	void bind(GlJobChainHandle& jobs, U32 unit);
 
 	/// Change filtering type
-	void setFilter(GlJobChainHandle& chain, Filter filter);
+	void setFilter(GlJobChainHandle& jobs, Filter filter);
 
 	/// Generate mips
-	void generateMipmaps(GlJobChainHandle& chain);
+	void generateMipmaps(GlJobChainHandle& jobs);
 
 	/// Set a texture parameter
-	void setParameter(GlJobChainHandle& chain, GLenum param, GLint value);
+	void setParameter(GlJobChainHandle& jobs, GLenum param, GLint value);
 
 	/// Get depth
 	U32 getDepth() const;
@@ -62,6 +63,39 @@ public:
 	U32 getHeight() const;
 };
 
+/// Sampler handle
+class GlSamplerHandle: public GlContainerHandle<GlSampler>
+{
+public:
+	typedef GlContainerHandle<GlSampler> Base;
+
+	typedef GlTextureFilter Filter;
+
+	/// @name Constructors/Destructor
+	/// @{
+
+	/// Create husk
+	GlSamplerHandle();
+
+	/// Create the sampler
+	explicit GlSamplerHandle(GlJobChainHandle& jobs);
+
+	~GlSamplerHandle();
+	/// @}
+
+	/// Bind to a unit
+	void bind(GlJobChainHandle& jobs, U32 unit);
+
+	/// Change filtering type
+	void setFilter(GlJobChainHandle& jobs, Filter filter);
+
+	/// Set a texture parameter
+	void setParameter(GlJobChainHandle& jobs, GLenum param, GLint value);
+
+	/// Bind default sampler
+	static void bindDefault(GlJobChainHandle& jobs, U32 unit);
+};
+
 /// @}
 
 } // end namespace anki

+ 8 - 0
include/anki/renderer/Ms.h

@@ -32,6 +32,11 @@ public:
 	{
 		return m_planes[1].m_depthRt;
 	}
+
+	GlTextureHandle& _getSmallDepthRt()
+	{
+		return m_smallDepthRt;
+	}
 	/// @}
 
 private:
@@ -51,6 +56,9 @@ private:
 		GlTextureHandle m_depthRt;
 	};
 
+	GlTextureHandle m_smallDepthRt; ///< A smaller depth buffer
+	GlFramebufferHandle m_smallDepthFb;
+
 	Ez m_ez; /// EarlyZ pass
 
 	/// One for multisampled and one for not. 0: multisampled, 1: not

+ 1 - 1
shaders/Final.frag.glsl

@@ -14,6 +14,6 @@ layout(location = 0) out vec3 outFragColor;
 void main()
 {
 	vec3 col = textureRt(uRasterImage, inTexCoords).rgb;
-	//vec3 col = vec3(textureRt(uRasterImage, inTexCoords).a);
+	//vec3 col = vec3((2.0 * 0.5) / (500.0 + 0.5 - textureRt(uRasterImage, inTexCoords).r * (500.0 - 0.5)));
 	outFragColor = col;
 }

+ 250 - 0
src/collision/TestsObbObb.cpp

@@ -0,0 +1,250 @@
+#include "anki/collision/Tests.h"
+#include "anki/Math.h"
+#include <cstring>
+
+namespace anki {
+namespace detail {
+
+//==============================================================================
+static F32 calcVectorDot3Internal(const F32* a, const F32* b, U stepA, U stepB)
+{
+	return a[0] * b[0] + a[stepA] * b[stepB] + a[2 * stepA] * b[2 * stepB];
+}
+
+static F32 calcVectorDot313(const F32* a, const F32* b)
+{ 
+	return calcVectorDot3Internal(a, b, 1, 3); 
+}
+static F32 calcVectorDot331(const F32* a, const F32* b) 
+{ 
+	return calcVectorDot3Internal(a, b, 3, 1); 
+}
+static F32 calcVectorDot333(const F32* a, const F32* b) 
+{ 
+	return calcVectorDot3Internal(a, b, 3, 3); 
+}
+static F32 calcVectorDot314(const F32* a, const F32* b) 
+{ 
+	return calcVectorDot3Internal(a, b, 1, 4); 
+}
+static F32 calcVectorDot341(const F32* a, const F32* b) 
+{ 
+	return calcVectorDot3Internal(a, b, 4, 1); 
+}
+static F32 calcVectorDot344(const F32* a, const F32* b) 
+{ 
+	return calcVectorDot3Internal(a, b, 4, 4); 
+}
+
+static void lineClosestApproach(
+	const Vec3& pa, const Vec3& ua,
+	const Vec3& pb, const Vec3& ub,
+	F32* alpha, F32* beta)
+{
+	Vec3 p;
+	p = pb - pa;
+	F32 uaub = ua.dot(ub);
+	F32 q1 =  ua.dot(p);
+	F32 q2 = -ub.dot(p);
+	F32 d = 1.0 - uaub * uaub;
+
+	if(d <= 0.0001)
+	{
+		*alpha = 0.0;
+		*beta = 0.0;
+	}
+	else 
+	{
+		d = 1.0 / d;
+		*alpha = (q1 + uaub * q2) * d;
+		*beta = (uaub * q1 + q2) * d;
+	}
+}
+
+// find all the intersection points between the 2D rectangle with vertices
+// at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]),
+// (p[2],p[3]),(p[4],p[5]),(p[6],p[7]).
+//
+// the intersection points are returned as x,y pairs in the 'ret' array.
+// the number of intersection points is returned by the function (this will
+// be in the range 0 to 8).
+static U intersectRectQuad(F32 h[2], F32 p[8], F32 ret[16])
+{
+	// q (and r) contain nq (and nr) coordinate points for the current (and
+	// chopped) polygons
+	I nq = 4;
+	U nr;
+	F32 buffer[16];
+	F32* q = p;
+	F32* r = ret;
+
+	for(I dir = 0; dir <= 1; dir++) 
+	{
+		// direction notation: xy[0] = x axis, xy[1] = y axis
+		for(I sign=-1; sign <= 1; sign += 2) 
+		{
+			// chop q along the line xy[dir] = sign*h[dir]
+			F32* pq = q;
+			F32* pr = r;
+			nr = 0;
+
+			for(I i = nq; i > 0; i--) 
+			{
+				// Go through all points in q and all lines between adjacent 
+				// points
+				if(sign * pq[dir] < h[dir]) 
+				{
+					// this point is inside the chopping line
+					pr[0] = pq[0];
+					pr[1] = pq[1];
+					pr += 2;
+					nr++;
+
+					if(nr & 8) 
+					{
+						q = r;
+						goto done;
+					}
+				}
+
+				F32* nextq = (i > 1) ? pq + 2 : q;
+
+				if((sign * pq[dir] < h[dir]) ^ (sign * nextq[dir] < h[dir])) 
+				{
+					// this line crosses the chopping line
+					pr[1 - dir] = pq[1 - dir] + (nextq[1 - dir] - pq[1 - dir]) 
+						/ (nextq[dir] - pq[dir]) * (sign * h[dir] - pq[dir]);
+					pr[dir] = sign * h[dir];
+					pr += 2;
+					++nr;
+					if(nr & 8) 
+					{
+						q = r;
+						goto done;
+					}
+				}
+				pq += 2;
+			}
+
+			q = r;
+			r = (q == ret) ? buffer : ret;
+			nq = nr;
+		}
+	}
+	
+done:
+	if(q != ret)
+	{
+		std::memcpy(ret, q, nr * 2 * sizeof(F32));
+	}
+
+	return nr;
+}
+
+// given n points in the plane (array p, of size 2*n), generate m points that
+// best represent the whole set. the definition of 'best' here is not
+// predetermined - the idea is to select points that give good box-box
+// collision detection behavior. the chosen point indexes are returned in the
+// array iret (of size m). 'i0' is always the first entry in the array.
+// n must be in the range [1..8]. m must be in the range [1..n]. i0 must be
+// in the range [0..n-1].
+static void cullPoints(I n, F32 p[], I m, I i0, I iret[])
+{
+	// compute the centroid of the polygon in cx,cy
+	I i, j;
+	F32 a, cx, cy, q;
+
+	if(n == 1) 
+	{
+		cx = p[0];
+		cy = p[1];
+	}
+	else if(n == 2) 
+	{
+		cx = 0.5 * (p[0] + p[2]);
+		cy = 0.5 * (p[1] + p[3]);
+	}
+	else 
+	{
+		a = 0.0;
+		cx = 0.0;
+		cy = 0.0;
+
+		for (i = 0; i < (n - 1); i++) 
+		{
+			q = p[i * 2] * p[i * 2 + 3] - p[ i * 2 + 2] * p[ i * 2 + 1];
+			a += q;
+			cx += q * (p[i * 2] + p[i * 2 + 2]);
+			cy += q * (p[i * 2 + 1] + p[i * 2 + 3]);
+		}
+
+		q = p[n * 2 - 2] * p[1] - p[0] * p[n * 2 - 1];
+		a = 1.0 / (3.0 * (a + q));
+		cx = a * (cx + q * (p[n * 2 - 2] + p[0]));
+		cy = a * (cy + q * (p[n * 2 - 1] + p[1]));
+	}
+
+	// compute the angle of each point w.r.t. the centroid
+	F32 A[8];
+	for(i = 0; i < n; i++) 
+	{
+		A[i] = atan2(p[i * 2 + 1] - cy, p[i * 2] - cx);
+	}
+
+	// search for points that have angles closest to A[i0] + i*(2*pi/m).
+	I avail[8];
+	for(i = 0; i < n; i++) 
+	{
+		avail[i] = 1;
+	}
+
+	avail[i0] = 0;
+	iret[0] = i0;
+	iret++;
+
+	for(j = 1; j < m; j++) 
+	{
+		a = (F32(j) * (2 * getPi<F32>() / m) + A[i0]);
+
+		if(a > getPi<F32>()) 
+		{
+			a -= 2.0 * getPi<F32>();
+		}
+
+		F32 maxdiff = 1e9, diff;
+#if ANKI_DEBUG == 1
+		*iret = i0;			// iret is not allowed to keep this value
+#endif
+		for(i = 0; i < n; i++) 
+		{
+			if(avail[i]) 
+			{
+				diff = abs(A[i] - a);
+
+				if(diff > getPi<F32>()) 
+				{
+					diff = 2.0 * getPi<F32>() - diff;
+				}
+
+				if(diff < maxdiff) 
+				{
+					maxdiff = diff;
+					*iret = i;
+				}
+			}
+		}
+
+		ANKI_ASSERT(*iret != i0);
+		avail[*iret] = 0;
+		iret++;
+	}
+}
+
+//==============================================================================
+U test(const Obb& a, const Obb& b, CollisionTempVector<ContactPoint>& points)
+{
+}
+
+} // end namespace detail
+} // end namespace anki
+

+ 4 - 3
src/gl/GlFramebuffer.cpp

@@ -194,15 +194,16 @@ void GlFramebuffer::bind(Bool invalidate)
 
 //==============================================================================
 void GlFramebuffer::blit(const GlFramebuffer& b, 
-	const Array<F32, 4>& sourceRect,
-	const Array<F32, 4>& destRect, Bool linear)
+	const Array<U32, 4>& sourceRect,
+	const Array<U32, 4>& destRect, 
+	GLbitfield attachmentMask, Bool linear)
 {
 	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_glName);
 	glBindFramebuffer(GL_READ_FRAMEBUFFER, b.m_glName);
 	glBlitFramebuffer(
 		sourceRect[0], sourceRect[1], sourceRect[2], sourceRect[3],
 		destRect[0], destRect[1], destRect[2], destRect[3], 
-		GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
+		attachmentMask,
 		linear ? GL_LINEAR : GL_NEAREST);
 }
 

+ 16 - 10
src/gl/GlFramebufferHandle.cpp

@@ -98,34 +98,40 @@ void GlFramebufferHandle::bind(GlJobChainHandle& jobs, Bool invalidate)
 //==============================================================================
 void GlFramebufferHandle::blit(GlJobChainHandle& jobs,
 	const GlFramebufferHandle& b, 
-	const Array<F32, 4>& sourceRect,
-	const Array<F32, 4>& destRect, Bool linear)
+	const Array<U32, 4>& sourceRect,
+	const Array<U32, 4>& destRect, 
+	GLbitfield attachmentMask,
+	Bool linear)
 {
 	class Job: public GlJob
 	{
 	public:
 		GlFramebufferHandle m_fbDest;
 		GlFramebufferHandle m_fbSrc;
-		Array<F32, 4> m_sourceRect;
-		Array<F32, 4> m_destRect;
+		Array<U32, 4> m_sourceRect;
+		Array<U32, 4> m_destRect;
+		GLbitfield m_attachmentMask;
 		Bool m_linear;
 
 		Job(GlFramebufferHandle& fbDest, const GlFramebufferHandle& fbSrc,
-			const Array<F32, 4>& sourceRect,
-			const Array<F32, 4>& destRect,
+			const Array<U32, 4>& sourceRect,
+			const Array<U32, 4>& destRect,
+			GLbitfield attachmentMask,
 			Bool linear)
 			:	m_fbDest(fbDest), m_fbSrc(fbSrc), m_sourceRect(sourceRect),
-				m_destRect(destRect), m_linear(linear)
+				m_destRect(destRect), m_attachmentMask(attachmentMask), 
+				m_linear(linear)
 		{}
 
 		void operator()(GlJobChain*)
 		{
-			m_fbSrc._get().blit(m_fbDest._get(), m_sourceRect, m_destRect, 
-				m_linear);
+			m_fbDest._get().blit(m_fbSrc._get(), m_sourceRect, m_destRect, 
+				m_attachmentMask, m_linear);
 		}
 	};
 
-	jobs._pushBackNewJob<Job>(*this, b, sourceRect, destRect, linear);
+	jobs._pushBackNewJob<Job>(
+		*this, b, sourceRect, destRect, attachmentMask, linear);
 }
 
 } // end namespace anki

+ 16 - 2
src/gl/GlJobManager.cpp

@@ -29,6 +29,12 @@ void GlJobManager::flushJobChain(GlJobChainHandle& jobs)
 	{
 		std::unique_lock<std::mutex> lock(m_mtx);
 
+		if(m_error.size() > 0)
+		{
+			throw ANKI_EXCEPTION("GL rendering thread failed with error:\n%s",
+				&m_error[0]);
+		}
+
 		// Set jobc
 		U64 diff = m_tail - m_head;
 
@@ -199,8 +205,16 @@ void GlJobManager::threadLoop()
 			++m_head;
 		}
 
-		// Exec jobs of chain
-		jobc._executeAllJobs();
+		try
+		{
+			// Exec jobs of chain
+			jobc._executeAllJobs();
+		}
+		catch(const std::exception& e)
+		{
+			std::unique_lock<std::mutex> lock(m_mtx);
+			m_error = e.what();
+		}
 	}
 
 	finish();

+ 30 - 1
src/gl/GlTexture.cpp

@@ -39,7 +39,7 @@ Bool isCompressedInternalFormat(const GLenum internalFormat)
 
 
 //==============================================================================
-// Texture                                                                     =
+// GlTexture                                                                   =
 //==============================================================================
 
 //==============================================================================
@@ -331,4 +331,33 @@ void GlTexture::generateMipmaps()
 	glGenerateMipmap(m_target);
 }
 
+//==============================================================================
+// GlSampler                                                                   =
+//==============================================================================
+
+//==============================================================================
+void GlSampler::setFilter(const Filter filterType)
+{
+	ANKI_ASSERT(isCreated());
+	switch(filterType)
+	{
+	case Filter::NEAREST:
+		glSamplerParameteri(m_glName, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		glSamplerParameteri(m_glName, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		break;
+	case Filter::LINEAR:
+		glSamplerParameteri(m_glName, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glSamplerParameteri(m_glName, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		break;
+	case Filter::TRILINEAR:
+		glSamplerParameteri(
+			m_glName, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+		glSamplerParameteri(m_glName, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		break;
+	default:
+		ANKI_ASSERT(0);
+		break;
+	}
+}
+
 } // end namespace anki

+ 140 - 6
src/gl/GlTextureHandle.cpp

@@ -5,6 +5,10 @@
 
 namespace anki {
 
+//==============================================================================
+// GlTextureHandle                                                             =
+//==============================================================================
+
 //==============================================================================
 /// Create texture job
 class GlTextureCreateJob: public GlJob
@@ -71,6 +75,7 @@ public:
 
 		GlHandleState oldState = m_tex._setState(GlHandleState::CREATED);
 		ANKI_ASSERT(oldState == GlHandleState::TO_BE_CREATED);
+		(void)oldState;
 	}
 };
 
@@ -184,25 +189,25 @@ void GlTextureHandle::bind(GlJobChainHandle& jobs, U32 unit)
 }
 
 //==============================================================================
-void GlTextureHandle::setFilter(GlJobChainHandle& chain, Filter filter)
+void GlTextureHandle::setFilter(GlJobChainHandle& jobs, Filter filter)
 {
 	ANKI_ASSERT(isCreated());
-	chain._pushBackNewJob<GlTextureSetFilterJob>(*this, filter);
+	jobs._pushBackNewJob<GlTextureSetFilterJob>(*this, filter);
 }
 
 //==============================================================================
-void GlTextureHandle::generateMipmaps(GlJobChainHandle& chain)
+void GlTextureHandle::generateMipmaps(GlJobChainHandle& jobs)
 {
 	ANKI_ASSERT(isCreated());
-	chain._pushBackNewJob<GlTextureGenMipsJob>(*this);
+	jobs._pushBackNewJob<GlTextureGenMipsJob>(*this);
 }
 
 //==============================================================================
-void GlTextureHandle::setParameter(GlJobChainHandle& chain, GLenum param, 
+void GlTextureHandle::setParameter(GlJobChainHandle& jobs, GLenum param, 
 	GLint value)
 {
 	ANKI_ASSERT(isCreated());
-	chain._pushBackNewJob<GlTextureSetParameterJob>(*this, param, value);
+	jobs._pushBackNewJob<GlTextureSetParameterJob>(*this, param, value);
 }
 
 //==============================================================================
@@ -226,5 +231,134 @@ U32 GlTextureHandle::getDepth() const
 	return _get().getDepth();
 }
 
+//==============================================================================
+// GlSamplerHandle                                                             =
+//==============================================================================
+
+//==============================================================================
+GlSamplerHandle::GlSamplerHandle()
+{}
+
+//==============================================================================
+GlSamplerHandle::GlSamplerHandle(GlJobChainHandle& jobs)
+{
+	class Job: public GlJob
+	{
+	public:
+		GlSamplerHandle m_sampler;
+
+		Job(const GlSamplerHandle& sampler)
+			: m_sampler(sampler)
+		{}
+
+		void operator()(GlJobChain* jobs)
+		{
+			ANKI_ASSERT(jobs);
+
+			GlSampler newSampler;
+			m_sampler._get() = std::move(newSampler);
+
+			GlHandleState oldState = m_sampler._setState(GlHandleState::CREATED);
+			ANKI_ASSERT(oldState == GlHandleState::TO_BE_CREATED);
+			(void)oldState;
+		}
+	};
+
+	jobs._pushBackNewJob<Job>(*this);
+}
+
+//==============================================================================
+GlSamplerHandle::~GlSamplerHandle()
+{}
+
+//==============================================================================
+void GlSamplerHandle::bind(GlJobChainHandle& jobs, U32 unit)
+{
+	class Job: public GlJob
+	{
+	public:
+		GlSamplerHandle m_sampler;
+		U32 m_unit;
+
+		Job(GlSamplerHandle& sampler, U32 unit)
+			: m_sampler(sampler), m_unit(unit)
+		{}
+
+		void operator()(GlJobChain*)
+		{
+			m_sampler._get().bind(m_unit);
+		}
+	};
+
+	jobs._pushBackNewJob<Job>(*this, unit);
+}
+
+//==============================================================================
+void GlSamplerHandle::setFilter(GlJobChainHandle& jobs, Filter filter)
+{
+	class Job: public GlJob
+	{
+	public:
+		GlSamplerHandle m_sampler;
+		GlSamplerHandle::Filter m_filter;
+
+		Job(const GlSamplerHandle& sampler, GlSamplerHandle::Filter filter)
+			: m_sampler(sampler), m_filter(filter)
+		{}
+
+		void operator()(GlJobChain*)
+		{
+			m_sampler._get().setFilter(m_filter);
+		}
+	};
+
+	jobs._pushBackNewJob<Job>(*this, filter);
+}
+
+//==============================================================================
+void GlSamplerHandle::setParameter(
+	GlJobChainHandle& jobs, GLenum param, GLint value)
+{
+	class Job: public GlJob
+	{
+	public:
+		GlSamplerHandle m_sampler;
+		GLenum m_param;
+		GLint m_value;
+
+		Job(GlSamplerHandle& sampler, GLenum param, GLint value)
+			: m_sampler(sampler), m_param(param), m_value(value)
+		{}
+
+		void operator()(GlJobChain*)
+		{
+			m_sampler._get().setParameter(m_param, m_value);
+		}
+	};
+
+	jobs._pushBackNewJob<Job>(*this, param, value);
+}
+
+//==============================================================================
+void GlSamplerHandle::bindDefault(GlJobChainHandle& jobs, U32 unit)
+{
+	class Job: public GlJob
+	{
+	public:
+		U32 m_unit;
+
+		Job(U32 unit)
+			: m_unit(unit)
+		{}
+
+		void operator()(GlJobChain*)
+		{
+			GlSamper::unbind(m_unit);
+		}
+	};
+
+	jobs._pushBackNewJob<Job>(*this, unit);
+}
+
 } // end namespace anki
 

+ 1 - 1
src/renderer/Drawer.cpp

@@ -197,7 +197,7 @@ public:
 			{
 				auto unit = glvar.getTextureUnit();
 
-				m_drawer->m_r->getMs()._getDepthRt().bind(m_jobs, unit);
+				m_drawer->m_r->getMs()._getSmallDepthRt().bind(m_jobs, unit);
 			}
 			break;
 		default:

+ 1 - 1
src/renderer/MainRenderer.cpp

@@ -77,7 +77,7 @@ void MainRenderer::render(SceneGraph& scene)
 		}
 
 		//rt = &getPps().getSslr()._getRt();
-		//rt = &getMs()._getRt0();
+		//rt = &getPps().getSsao().getRt();
 
 		rt->setFilter(lastJobs, GlTextureHandle::Filter::LINEAR);
 		rt->bind(lastJobs, 0);

+ 28 - 1
src/renderer/Ms.cpp

@@ -36,7 +36,7 @@ void Ms::createRt(U32 index, U32 samples)
 		{plane.m_rt1, GL_COLOR_ATTACHMENT1},
 		{plane.m_depthRt, GL_DEPTH_ATTACHMENT}});
 
-	jobs.flush();
+	jobs.finish();
 }
 
 //==============================================================================
@@ -50,6 +50,26 @@ void Ms::init(const RendererInitializer& initializer)
 		}
 		createRt(1, 1);
 
+		// Init small depth 
+		{
+			m_r->createRenderTarget(
+				getAlignedRoundUp(16, m_r->getWidth() / 3) , 
+				getAlignedRoundUp(16, m_r->getHeight() / 3),
+				GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
+				GL_UNSIGNED_INT, 1, m_smallDepthRt);
+
+			GlManager& gl = GlManagerSingleton::get();
+			GlJobChainHandle jobs(&gl);
+
+			//m_smallDepthRt.setFilter(jobs, GlTextureHandle::Filter::LINEAR);
+
+			m_smallDepthFb = GlFramebufferHandle(
+				jobs,
+				{{m_smallDepthRt, GL_DEPTH_ATTACHMENT}});
+
+			jobs.finish();
+		}
+
 		m_ez.init(initializer);
 	}
 	catch(const std::exception& e)
@@ -119,6 +139,13 @@ void Ms::run(GlJobChainHandle& jobs)
 		ANKI_ASSERT(0 && "TODO");
 	}
 
+	// Blit big depth buffer to small one
+	m_smallDepthFb.blit(jobs, m_planes[1].m_fb, 
+		{{0, 0, m_planes[1].m_depthRt.getWidth(), 
+			m_planes[1].m_depthRt.getHeight()}},
+		{{0, 0, m_smallDepthRt.getWidth(), m_smallDepthRt.getHeight()}},
+		GL_DEPTH_BUFFER_BIT, false);
+
 	jobs.enableDepthTest(false);
 }
 

+ 1 - 1
src/renderer/Ssao.cpp

@@ -238,7 +238,7 @@ void Ssao::run(GlJobChainHandle& jobs)
 	m_ssaoPpline.bind(jobs);
 
 	m_uniformsBuff.bindShaderBuffer(jobs, 0);
-	m_r->getMs()._getDepthRt().bind(jobs, 0); // Depth
+	m_r->getMs()._getSmallDepthRt().bind(jobs, 0); // Depth
 	m_r->getMs()._getRt1().bind(jobs, 1); // Normals
 	m_noiseTex.bind(jobs, 2);
 

+ 1 - 1
src/renderer/Sslr.cpp

@@ -81,7 +81,7 @@ void Sslr::run(GlJobChainHandle& jobs)
 
 	m_reflectionPpline.bind(jobs);
 	m_r->getIs()._getRt().bind(jobs, 0);
-	m_r->getMs()._getDepthRt().bind(jobs, 1);
+	m_r->getMs()._getSmallDepthRt().bind(jobs, 1);
 	m_r->getMs()._getRt1().bind(jobs, 2);
 	m_r->getPps().getSsao().m_uniformsBuff.bindShaderBuffer(jobs, 0);
 

+ 2 - 2
src/util/Exception.cpp

@@ -45,7 +45,7 @@ Exception::Exception(const char* file, I line, const char* func,
 
 	m_err = synthErr(out, file, line, func);
 
-#if ANKI_ABORT_ON_THROW
+#if ANKI_ABORT_ON_THROW == 1
 	std::cerr << m_err << std::endl;
 	abort();
 #endif
@@ -59,7 +59,7 @@ Exception::Exception(const Exception& e) noexcept
 	m_err = (char*)mallocAligned(strlen(e.m_err) + 1, 1);
 	strcpy(m_err, e.m_err);
 
-#if ANKI_ABORT_ON_THROW
+#if ANKI_ABORT_ON_THROW == 1
 	std::cerr << m_err << std::endl;
 	abort();
 #endif

+ 2 - 2
testapp/Main.cpp

@@ -361,7 +361,7 @@ void mainLoopExtra()
 	F32 dist = 0.1;
 	F32 ang = toRad(1.5);
 	F32 scale = 0.01;
-	F32 mouseSensivity = 6.0;
+	F32 mouseSensivity = 9.0;
 
 	// move the camera
 	static MoveComponent* mover = 
@@ -648,7 +648,7 @@ void initSubsystems(int argc, char* argv[])
 	initializer.set("pps.sslr.enabled", true);
 	initializer.set("pps.sslr.renderingQuality", 0.35);
 	initializer.set("pps.sslr.blurringIterationsCount", 1);
-	initializer.set("pps.ssao.blurringIterationsCount", 1);
+	initializer.set("pps.ssao.blurringIterationsCount", 2);
 	initializer.set("pps.ssao.enabled", true);
 	initializer.set("pps.ssao.renderingQuality", 0.35);
 	initializer.set("pps.bl.enabled", true);