Przeglądaj źródła

Fixing bugs and refactoring FBOs

Panagiotis Christopoulos Charitos 12 lat temu
rodzic
commit
faa97a79fa

+ 6 - 4
include/anki/Config.h.cmake

@@ -17,11 +17,13 @@
 #define ANKI_OS_IOS 4
 #define ANKI_OS_WINDOWS 5
 
-#if defined( __WIN32__ ) || defined( _WIN32 )
+#if defined(__WIN32__) || defined(_WIN32)
 #	define ANKI_OS ANKI_OS_WINDOWS
-#elif defined( __APPLE_CC__)
-#	if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000 \
-	|| __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+#elif defined(__APPLE_CC__)
+#	if (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) \
+		&& __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 40000) \
+	|| (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \
+		&& __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
 #		define ANKI_OS ANKI_OS_IOS
 #	else
 #		define ANKI_OS ANKI_OS_MACOS

+ 70 - 44
include/anki/gl/Fbo.h

@@ -3,6 +3,7 @@
 
 #include "anki/gl/GlObject.h"
 #include "anki/util/Array.h"
+#include "anki/Math.h"
 #include <initializer_list>
 
 namespace anki {
@@ -13,30 +14,56 @@ class Texture;
 /// @{
 
 /// Frame buffer object. The class is actually a wrapper to avoid common 
-/// mistakes. It only supports binding at both draw and read targets
+/// mistakes
 class Fbo: public GlObjectContextNonSharable
 {
 public:
-	static const U MAX_ATTACHMENTS = 8;
+	static const U MAX_COLOR_ATTACHMENTS = 4;
 
 	typedef GlObjectContextNonSharable Base;
 
+	/// Used as an argument on FBO creation
+	struct Attachment
+	{
+		const Texture* texture;
+		GLenum attachmentPoint;
+		I32 layer; ///< Layer or face
+
+		Attachment(const Texture* tex, GLenum attachmentPoint_)
+			:	texture(tex),
+				attachmentPoint(attachmentPoint_),
+				layer(-1)
+		{
+			ANKI_ASSERT(texture != nullptr);
+		}
+
+		Attachment(const Texture* tex, GLenum attachmentPoint_, I32 layer_)
+			:	texture(tex), 
+				attachmentPoint(attachmentPoint_), 
+				layer(layer_)
+		{
+			ANKI_ASSERT(texture != nullptr);
+			ANKI_ASSERT(layer != -1);
+		}
+	};
+
 	/// FBO target
-	enum FboTarget
+	enum Target
 	{
-		FT_DRAW = 1 << 1,
-		FT_READ = 1 << 2,
-		FT_ALL = FT_DRAW | FT_READ
+		DRAW_TARGET = 1 << 1,
+		READ_TARGET = 1 << 2,
+		ALL_TARGETS = DRAW_TARGET | READ_TARGET
 	};
 
 	/// @name Constructors/Destructor
 	/// @{
 	Fbo()
-		: attachmentsCount(0)
+		: colorAttachmentsCount(0)
 	{}
 
 	/// Move
 	Fbo(Fbo&& b)
+		: Fbo()
 	{
 		*this = std::move(b);
 	}
@@ -53,54 +80,50 @@ public:
 	{
 		destroy();
 		Base::operator=(std::forward<Base>(b));
-		attachmentsCount = b.attachmentsCount;
-		b.attachmentsCount = 0;
+		colorAttachmentsCount = b.colorAttachmentsCount;
+		b.colorAttachmentsCount = 0;
 		return *this;
 	}
 	/// @}
 
+	/// Creates a new FBO
+	void create(const std::initializer_list<Attachment>& attachments);
+
+	/// Destroy it
+	void destroy();
+
 	/// Binds FBO
-	void bind(const FboTarget target = FT_ALL, Bool noReadbacks = false) const;
+	void bind(Bool invalidate, const Target target = ALL_TARGETS) const
+	{
+		ANKI_ASSERT(isCreated());
+		checkNonSharable();
+		bindInternal(this, invalidate, target);
+	}
 
 	/// Unbind all targets. Unbinds both draw and read FBOs so the active is
 	/// the default FBO
-	static void bindDefault(const FboTarget target = FT_ALL,
-		Bool noReadbacks = false);
-
-	/// Returns true if the FBO is ready for draw calls
-	Bool isComplete() const;
-
-	/// Set the color attachments of this FBO
-	void setColorAttachments(
-		const std::initializer_list<const Texture*>& textures);
-
-	/// Set other attachment
-	void setOtherAttachment(GLenum attachment, const Texture& tex, 
-		const I32 layer = -1, const I32 face = -1);
-
-	/// Blit framebuffer
-	void blit(const Fbo& source, U32 srcX0, U32 srcY0, U32 srcX1, U32 srcY1, 
-		U32 dstX0, U32 dstY0, U32 dstX1, U32 dstY1, GLbitfield mask,
-		GLenum filter)
+	static void bindDefault(
+		Bool invalidate, const Target target = ALL_TARGETS)
 	{
-		source.bind(FT_READ);
-		bind(FT_DRAW);
-		glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, 
-			dstY1, mask, filter);
+		bindInternal(nullptr, invalidate, target);
 	}
 
-	/// Creates a new FBO
-	void create();
-
-	/// Destroy it
-	void destroy();
+	/// Blit another framebuffer to this one
+	void blitFrom(const Fbo& source, const UVec2& srcMin, const UVec2& srcMax, 
+		const UVec2& dstMin, const UVec2& dstMax, 
+		GLbitfield mask, GLenum filter)
+	{
+		source.bind(false, READ_TARGET);
+		bind(false, DRAW_TARGET);
+		glBlitFramebuffer(srcMin.x(), srcMin.y(), srcMax.x(), srcMax.y(), 
+			dstMin.x(), dstMin.y(), dstMax.x(), dstMax.y(), mask, filter);
+	}	
 
 private:
 	static thread_local const Fbo* currentRead;
 	static thread_local const Fbo* currentDraw;
 
-	Array<GLenum, MAX_ATTACHMENTS> attachments;
-	U8 attachmentsCount;
+	U8 colorAttachmentsCount;
 
 	static GLuint getCurrentFboGlId()
 	{
@@ -123,11 +146,14 @@ private:
 		return i;
 	}
 
-	void invalidateInternal() const
-	{
-		glInvalidateFramebuffer(GL_FRAMEBUFFER, attachmentsCount, 
-			&attachments[0]);
-	}
+	/// Bind an FBO
+	/// @param fbo May be nullptr
+	static void bindInternal(const Fbo* fbo, Bool invalidate, 
+		const Target target);
+
+	/// Attach texture internal
+	void attachTextureInternal(GLenum attachment, const Texture& tex, 
+		const I32 layer);
 };
 /// @}
 

+ 0 - 5
include/anki/renderer/Renderer.h

@@ -240,11 +240,6 @@ public:
 		return distance / lodDistance;
 	}
 
-	/// On some GPUs its optimal to clean after binding to an FBO and there is
-	/// no use for it's previous contents. For other GPUs the clear will be 
-	/// skipped
-	void clearAfterBindingFbo(const GLenum cap);
-
 private:
 	/// @name Rendering stages
 	/// @{

+ 20 - 1
src/core/Logger.cpp

@@ -107,7 +107,26 @@ void Logger::defaultSystemMessageHandler(void*, const Info& info)
 	__android_log_print(andMsgType, "AnKi", "(%s:%d %s) %s", info.file,
 		info.line, info.func, info.msg);
 #else
-	std::cout << "(" << info.file << ":" << info.line << " "
+	std::ostream* out = NULL;
+	const char* x = NULL;
+
+	switch(info.type)
+	{
+	case Logger::LMT_NORMAL:
+		out = &std::cout;
+		x = "Info";
+		break;
+	case Logger::LMT_ERROR:
+		out = &std::cerr;
+		x = "Error";
+		break;
+	case Logger::LMT_WARNING:
+		out = &std::cerr;
+		x = "Warn";
+		break;
+	}
+
+	(*out) << "(" << info.file << ":" << info.line << " "
 		<< info.func << ") " << x << ": " << info.msg << std::endl;
 #endif
 }

+ 90 - 129
src/gl/Fbo.cpp

@@ -1,5 +1,6 @@
 #include "anki/gl/Fbo.h"
 #include "anki/gl/Texture.h"
+#include "anki/gl/GlState.h"
 #include "anki/util/Array.h"
 
 namespace anki {
@@ -9,18 +10,56 @@ namespace anki {
 thread_local const Fbo* Fbo::currentRead = nullptr;
 thread_local const Fbo* Fbo::currentDraw = nullptr;
 
-static const Array<GLenum, 8> colorAttachments = {{
-	GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
-	GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5,
-	GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7}};
+static const Array<GLenum, Fbo::MAX_COLOR_ATTACHMENTS + 1> 
+	ATTACHMENT_TOKENS = {{
+	GL_DEPTH_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, 
+	GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}};
 
 //==============================================================================
-void Fbo::create()
+void Fbo::create(const std::initializer_list<Attachment>& attachments)
 {
 	ANKI_ASSERT(!isCreated());
 	crateNonSharable();
+
+	// Create name
 	glGenFramebuffers(1, &glId);
 	ANKI_ASSERT(glId != 0);
+
+	// Bind
+	bind(false, ALL_TARGETS);
+
+	// Attach textures
+	colorAttachmentsCount = 0;
+	for(const Attachment& attachment : attachments)
+	{
+		// Set some values
+		const GLenum max = GL_COLOR_ATTACHMENT0 + MAX_COLOR_ATTACHMENTS;
+		if(attachment.attachmentPoint >= GL_COLOR_ATTACHMENT0 
+			&& attachment.attachmentPoint < max)
+		{
+			ANKI_ASSERT(colorAttachmentsCount == 
+				attachment.attachmentPoint - GL_COLOR_ATTACHMENT0);
+
+			++colorAttachmentsCount;
+		}
+		else
+		{
+			ANKI_ASSERT(
+				attachment.attachmentPoint == GL_DEPTH_STENCIL_ATTACHMENT
+				|| attachment.attachmentPoint == GL_DEPTH_ATTACHMENT
+				|| attachment.attachmentPoint == GL_STENCIL_ATTACHMENT);
+		}
+
+		attachTextureInternal(attachment.attachmentPoint, *attachment.texture,
+			attachment.layer);
+	}
+
+	// Check completeness
+	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	if(status != GL_FRAMEBUFFER_COMPLETE)
+	{
+		throw ANKI_EXCEPTION("FBO is incomplete");
+	}
 }
 
 //==============================================================================
@@ -29,157 +68,81 @@ void Fbo::destroy()
 	checkNonSharable();
 	if(isCreated())
 	{
-		bindDefault();
+		bindDefault(false, ALL_TARGETS);
 		glDeleteFramebuffers(1, &glId);
 		glId = 0;
+		colorAttachmentsCount = 0;
 	}
 }
 
 //==============================================================================
-void Fbo::bind(const FboTarget target, Bool noReadbacks) const
+void Fbo::bindInternal(const Fbo* fbo, Bool invalidate, const Target target)
 {
-	ANKI_ASSERT(isCreated());
-	checkNonSharable();
+	GLenum glTarget = GL_FRAMEBUFFER;
+	GLuint name = fbo != nullptr ? fbo->glId : 0;
 
-	if(target == FT_ALL)
+	// Bind
+	if(target == ALL_TARGETS)
 	{
-		if(currentDraw != this || currentRead != this)
+		if(currentDraw != fbo || currentRead != fbo)
 		{
-			glBindFramebuffer(GL_FRAMEBUFFER, glId);
-			currentDraw = currentRead = this;
+			glBindFramebuffer(glTarget, name);
+			currentDraw = currentRead = fbo;
 		}
-
-#if ANKI_GL == ANKI_GL_ES
-		if(noReadbacks)
-		{
-			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT 
-				| GL_STENCIL_BUFFER_BIT);
-		}
-#endif
 	}
-	else if(target == FT_DRAW)
+	else if(target == DRAW_TARGET)
 	{
-		if(currentDraw != this)
+		glTarget = GL_DRAW_FRAMEBUFFER;
+		if(currentDraw != fbo)
 		{
-			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, glId);
-			currentDraw = this;
+			glBindFramebuffer(glTarget, name);
+			currentDraw = fbo;
 		}
-
-#if ANKI_GL == ANKI_GL_ES
-		if(noReadbacks)
-		{
-			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT 
-				| GL_STENCIL_BUFFER_BIT);
-		}
-#endif
 	}
 	else
 	{
-		ANKI_ASSERT(target == FT_READ);
-		if(currentRead != this)
-		{
-			glBindFramebuffer(GL_READ_FRAMEBUFFER, glId);
-			currentRead = this;
-		}
-
-		ANKI_ASSERT(noReadbacks == false && "Doesn't make sense");
-	}
-}
-
-//==============================================================================
-void Fbo::bindDefault(const FboTarget target, Bool noReadbacks)
-{
-	if(target == FT_ALL)
-	{
-		if(currentDraw != nullptr || currentRead != nullptr)
-		{
-			glBindFramebuffer(GL_FRAMEBUFFER, 0);
-			currentDraw = currentRead = nullptr;
-		}
+		ANKI_ASSERT(target == READ_TARGET);
 
-#if ANKI_GL == ANKI_GL_ES
-		if(noReadbacks)
+		glTarget = GL_READ_FRAMEBUFFER;
+		if(currentRead != fbo)
 		{
-			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT 
-				| GL_STENCIL_BUFFER_BIT);
+			glBindFramebuffer(glTarget, name);
+			currentRead = fbo;
 		}
-#endif
 	}
-	else if(target == FT_DRAW)
+
+	// Set the drawbuffers
+	if(name != 0)
 	{
-		if(currentDraw != nullptr)
-		{
-			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-			currentDraw = nullptr;
-		}
+		glDrawBuffers(fbo->colorAttachmentsCount, 
+			&ATTACHMENT_TOKENS[1]);
 
-#if ANKI_GL == ANKI_GL_ES
-		if(noReadbacks)
+		// Invalidate
+		if(invalidate)
 		{
-			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT 
+			glInvalidateFramebuffer(
+				glTarget, ATTACHMENT_TOKENS.size(), &ATTACHMENT_TOKENS[0]);
+
+			if(name == 0
+				&& GlStateCommonSingleton::get().getGpu() == 
+					GlStateCommon::GPU_ARM)
+			{
+				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
+					| GL_STENCIL_BUFFER_BIT);
+			}
+
+#if ANKI_DEBUG == 1
+			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
 				| GL_STENCIL_BUFFER_BIT);
-		}
 #endif
-	}
-	else
-	{
-		ANKI_ASSERT(target == FT_READ);
-		if(currentRead != nullptr)
-		{
-			glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
-			currentRead = nullptr;
 		}
-
-		ANKI_ASSERT(noReadbacks == false && "Doesn't make sense");
 	}
 }
 
 //==============================================================================
-Bool Fbo::isComplete() const
+void Fbo::attachTextureInternal(GLenum attachment, const Texture& tex, 
+	const I32 layer)
 {
-	bind();
-
-	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-	return status == GL_FRAMEBUFFER_COMPLETE;
-}
-
-//==============================================================================
-void Fbo::setColorAttachments(const std::initializer_list<const Texture*>& 
-	textures)
-{
-	ANKI_ASSERT(textures.size() > 0);
-
-	bind();
-
-	// Set number of color attachments
-	glDrawBuffers(textures.size(), &colorAttachments[0]);
-
-	// Set attachments
-	U i = 0;
-	for(const Texture* tex : textures)
-	{
-#if ANKI_GL == ANKI_GL_DESKTOP
-		ANKI_ASSERT(tex->getTarget() == GL_TEXTURE_2D 
-			|| tex->getTarget() == GL_TEXTURE_2D_MULTISAMPLE);
-#else
-		ANKI_ASSERT(tex->getTarget() == GL_TEXTURE_2D);
-#endif
-
-		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-			tex->getTarget(), tex->getGlId(), 0);
-
-		attachments[attachmentsCount++] = GL_COLOR_ATTACHMENT0 + i;
-
-		++i;
-	}
-}
-
-//==============================================================================
-void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex, 
-	const I32 layer, const I32 face)
-{
-	bind();
-
 	const GLenum target = GL_FRAMEBUFFER;
 	switch(tex.getTarget())
 	{
@@ -187,18 +150,18 @@ void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex,
 #if ANKI_GL == ANKI_GL_DESKTOP
 	case GL_TEXTURE_2D_MULTISAMPLE:
 #endif
-		ANKI_ASSERT(layer < 0 && face < 0);
+		ANKI_ASSERT(layer < 0);
 		glFramebufferTexture2D(target, attachment,
 			tex.getTarget(), tex.getGlId(), 0);
 		break;
 	case GL_TEXTURE_CUBE_MAP:
-		ANKI_ASSERT(layer < 0 && face >= 0);
+		ANKI_ASSERT(layer >= 0 && layer < 6);
 		glFramebufferTexture2D(target, attachment,
-			GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, tex.getGlId(), 0);
+			GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, tex.getGlId(), 0);
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
-		ANKI_ASSERT(layer >= 0 && face < 0);
+		ANKI_ASSERT(layer >= 0);
 		ANKI_ASSERT((GLuint)layer < tex.getDepth());
 		glFramebufferTextureLayer(target, attachment,
 			tex.getGlId(), 0, layer);
@@ -207,8 +170,6 @@ void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex,
 		ANKI_ASSERT(0);
 		break;
 	}
-
-	attachments[attachmentsCount++] = attachment;
 }
 
 } // end namespace anki

+ 7 - 12
src/renderer/Dbg.cpp

@@ -20,23 +20,18 @@ void Dbg::init(const RendererInitializer& initializer)
 
 	try
 	{
-		fbo.create();
-
 		// Chose the correct color FAI
 		if(r->getPps().getEnabled())
 		{
-			fbo.setColorAttachments({&r->getPps().getFai()});
+			fbo.create({
+				{&r->getPps().getFai(), GL_COLOR_ATTACHMENT0},
+				{&r->getMs().getDepthFai(), GL_DEPTH_ATTACHMENT}});
 		}
 		else
 		{
-			fbo.setColorAttachments({&r->getIs().getFai()});
-		}
-
-		fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
-
-		if(!fbo.isComplete())
-		{
-			throw ANKI_EXCEPTION("FBO is incomplete");
+			fbo.create({
+				{&r->getIs().getFai(), GL_COLOR_ATTACHMENT0},
+				{&r->getMs().getDepthFai(), GL_DEPTH_ATTACHMENT}});
 		}
 
 		drawer.reset(new DebugDrawer);
@@ -53,7 +48,7 @@ void Dbg::run()
 {
 	ANKI_ASSERT(enabled);
 
-	fbo.bind();
+	fbo.bind(false);
 	SceneGraph& scene = r->getSceneGraph();
 
 	GlStateSingleton::get().disable(GL_BLEND);

+ 4 - 12
src/renderer/Hdr.cpp

@@ -17,12 +17,7 @@ void Hdr::initFbo(Fbo& fbo, Texture& fai)
 	fai.setFiltering(Texture::TFT_LINEAR);
 
 	// create FBO
-	fbo.create();
-	fbo.setColorAttachments({&fai});
-	if(!fbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("Fbo not complete");
-	}
+	fbo.create({{&fai, GL_COLOR_ATTACHMENT0}});
 }
 
 //==============================================================================
@@ -110,8 +105,7 @@ void Hdr::run()
 	//vblurFai.setFiltering(Texture::TFT_NEAREST);
 
 	// pass 0
-	vblurFbo.bind();
-	r->clearAfterBindingFbo(GL_COLOR_BUFFER_BIT);
+	vblurFbo.bind(true);
 	toneSProg->bind();
 
 	if(parameterUpdateTimestamp > commonUboUpdateTimestamp)
@@ -128,8 +122,7 @@ void Hdr::run()
 	for(U32 i = 0; i < blurringIterationsCount; i++)
 	{
 		// hpass
-		hblurFbo.bind();
-		r->clearAfterBindingFbo(GL_COLOR_BUFFER_BIT);
+		hblurFbo.bind(true);
 		hblurSProg->bind();
 		if(i == 0)
 		{
@@ -138,8 +131,7 @@ void Hdr::run()
 		r->drawQuad();
 
 		// vpass
-		vblurFbo.bind();
-		r->clearAfterBindingFbo(GL_COLOR_BUFFER_BIT);
+		vblurFbo.bind(true);
 		vblurSProg->bind();
 		if(i == 0)
 		{

+ 3 - 9
src/renderer/Is.cpp

@@ -498,13 +498,7 @@ void Is::initInternal(const RendererInitializer& initializer)
 	// IS FBO
 	fai.create2dFai(r->getWidth(), r->getHeight(), GL_RGB8,
 		GL_RGB, GL_UNSIGNED_BYTE);
-	fbo.create();
-	fbo.setColorAttachments({&fai});
-
-	if(!fbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("Fbo not complete");
-	}
+	fbo.create({{&fai, GL_COLOR_ATTACHMENT0}});
 
 	//
 	// Init the quad
@@ -853,14 +847,14 @@ void Is::setState()
 
 	if(drawToDefaultFbo)
 	{
-		Fbo::bindDefault(Fbo::FT_ALL, true);
+		Fbo::bindDefault(true, Fbo::ALL_TARGETS);
 
 		GlStateSingleton::get().setViewport(
 			0, 0, r->getWindowWidth(), r->getWindowHeight());
 	}
 	else
 	{
-		fbo.bind(Fbo::FT_ALL, true);
+		fbo.bind(true);
 
 		GlStateSingleton::get().setViewport(
 			0, 0, r->getWidth(), r->getHeight());

+ 3 - 8
src/renderer/Lf.cpp

@@ -105,13 +105,8 @@ void Lf::initInternal(const RendererInitializer& initializer)
 		r->getPps().getHdr().getFai().getHeight(), 
 		GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
 
-	fbo.create();
-	fbo.setColorAttachments({&fai});
-	if(!fbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("Fbo not complete");
-	}
-
+	fbo.create({{&fai, GL_COLOR_ATTACHMENT0}});
+	
 	// Textures
 	lensDirtTex.load("engine_data/lens_dirt.ankitex");
 }
@@ -128,7 +123,7 @@ void Lf::run()
 	// Set the common state
 	const Texture& inTex = r->getPps().getHdr().getFai();
 
-	fbo.bind();
+	fbo.bind(true);
 	pseudoProg->bind();
 	pseudoProg->findUniformVariable("tex").set(inTex);
 	pseudoProg->findUniformVariable("lensDirtTex").set(*lensDirtTex);

+ 3 - 1
src/renderer/MainRenderer.cpp

@@ -46,7 +46,7 @@ void MainRenderer::render(SceneGraph& scene)
 
 	if(notDrawnToDefault)
 	{
-		Fbo::bindDefault(Fbo::FT_ALL, true); // Bind the window framebuffer
+		Fbo::bindDefault(true, Fbo::ALL_TARGETS); // Bind the window framebuffer
 
 		GlStateSingleton::get().setViewport(
 			0, 0, getWindowWidth(), getWindowHeight());
@@ -65,6 +65,8 @@ void MainRenderer::render(SceneGraph& scene)
 			fai = &getIs().getFai();
 		}
 
+		//fai = &getPps().getHdr().getFai();
+
 		fai->setFiltering(Texture::TFT_LINEAR);
 
 		blitProg->findUniformVariable("rasterImage").set(*fai);

+ 22 - 14
src/renderer/Ms.cpp

@@ -39,21 +39,18 @@ void Ms::createFbo(U index, U samples)
 		GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
 		GL_UNSIGNED_INT, samples);
 
-	fbo[index].create();
-
 	if(r->getUseMrt())
 	{
-		fbo[index].setColorAttachments({&fai0[index], &fai1[index]});
+		fbo[index].create({
+			{&fai0[index], GL_COLOR_ATTACHMENT0}, 
+			{&fai1[index], GL_COLOR_ATTACHMENT1},
+			{&depthFai[index], GL_DEPTH_ATTACHMENT}});
 	}
 	else
 	{
-		fbo[index].setColorAttachments({&fai0[index]});
-	}
-	fbo[index].setOtherAttachment(GL_DEPTH_ATTACHMENT, depthFai[index]);
-
-	if(!fbo[index].isComplete())
-	{
-		throw ANKI_EXCEPTION("FBO is incomplete");
+		fbo[index].create({
+			{&fai0[index], GL_COLOR_ATTACHMENT0}, 
+			{&depthFai[index], GL_DEPTH_ATTACHMENT}});
 	}
 }
 
@@ -84,14 +81,22 @@ void Ms::run()
 	// Chose the multisampled or the singlesampled FBO
 	if(r->getSamples() > 1)
 	{
-		fbo[0].bind();
+		fbo[0].bind(true);
 	}
 	else
 	{
-		fbo[1].bind();
+		fbo[1].bind(true);
 	}
 
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+	if(GlStateCommonSingleton::get().getGpu() == GlStateCommon::GPU_ARM)
+	{
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT 
+			| GL_STENCIL_BUFFER_BIT);
+	}
+	else
+	{
+		glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+	}
 
 	gl.setViewport(0, 0, r->getWidth(), r->getHeight());
 	gl.disable(GL_BLEND);
@@ -122,7 +127,8 @@ void Ms::run()
 	// If there is multisampling then resolve to singlesampled
 	if(r->getSamples() > 1)
 	{
-		fbo[0].bind(Fbo::FT_READ);
+#if 0
+		fbo[0].bind(false, Fbo::FT_READ);
 		glReadBuffer(GL_COLOR_ATTACHMENT1);
 		fbo[1].bind(Fbo::FT_DRAW);
 		static const GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT1};
@@ -143,6 +149,8 @@ void Ms::run()
 			0, 0, r->getWidth(), r->getHeight(),
 			GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
 			GL_NEAREST);
+#endif
+		ANKI_ASSERT(0 && "TODO");
 	}
 
 	// Gen mips

+ 3 - 8
src/renderer/Pps.cpp

@@ -34,12 +34,7 @@ void Pps::initInternal(const RendererInitializer& initializer)
 	fai.create2dFai(r->getWidth(), r->getHeight(), GL_RGB8, GL_RGB,
 		GL_UNSIGNED_BYTE);
 
-	fbo.create();
-	fbo.setColorAttachments({&fai});
-	if(!fbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("Fbo not complete");
-	}
+	fbo.create({{&fai, GL_COLOR_ATTACHMENT0}});
 
 	// SProg
 	std::string pps = "";
@@ -118,13 +113,13 @@ void Pps::run()
 
 	if(drawToDefaultFbo)
 	{
-		Fbo::bindDefault(Fbo::FT_ALL, true);
+		Fbo::bindDefault(true);
 		GlStateSingleton::get().setViewport(
 			0, 0, r->getWindowWidth(), r->getWindowHeight());
 	}
 	else
 	{
-		fbo.bind(Fbo::FT_ALL, true);
+		fbo.bind(true);
 		GlStateSingleton::get().setViewport(
 			0, 0, r->getWidth(), r->getHeight());
 	}

+ 0 - 9
src/renderer/Renderer.cpp

@@ -262,13 +262,4 @@ void Renderer::calcLimitsOfNearPlane(const PerspectiveCamera& pcam,
 	limitsOfNearPlane.x() = tan(0.5 * pcam.getFovX());
 }
 
-//==============================================================================
-void Renderer::clearAfterBindingFbo(const GLenum cap)
-{
-	if(GlStateCommonSingleton::get().getGpu() == GlStateCommon::GPU_ARM)
-	{
-		glClear(cap);
-	}
-}
-
 } // end namespace anki

+ 2 - 4
src/renderer/Sm.cpp

@@ -60,8 +60,7 @@ void Sm::init(const RendererInitializer& initializer)
 	for(Shadowmap& sm : sms)
 	{
 		sm.layerId = layer;
-		sm.fbo.create();
-		sm.fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, sm2DArrayTex, layer, -1);
+		sm.fbo.create({{&sm2DArrayTex, GL_DEPTH_ATTACHMENT, (I32)layer}});
 
 		++layer;
 	}
@@ -199,8 +198,7 @@ Sm::Shadowmap* Sm::doLight(Light& light)
 	//
 	// Render
 	//
-	sm.fbo.bind();
-	r->clearAfterBindingFbo(GL_DEPTH_BUFFER_BIT);
+	sm.fbo.bind(true);
 	glClear(GL_DEPTH_BUFFER_BIT);
 
 	//std::cout << "Shadowmap for: " << &sm << std::endl;

+ 4 - 11
src/renderer/Ssao.cpp

@@ -68,14 +68,7 @@ void Ssao::createFbo(Fbo& fbo, Texture& fai, U width, U height)
 
 	// Set to bilinear because the blurring techniques take advantage of that
 	fai.setFiltering(Texture::TFT_LINEAR);
-
-	fbo.create();
-	fbo.setColorAttachments({&fai});
-
-	if(!fbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("Fbo not complete");
-	}
+	fbo.create({{&fai, GL_COLOR_ATTACHMENT0}});
 }
 
 //==============================================================================
@@ -213,7 +206,7 @@ void Ssao::run()
 
 	// 1st pass
 	//
-	vblurFbo.bind(Fbo::FT_ALL, true);
+	vblurFbo.bind(true);
 	GlStateSingleton::get().setViewport(0, 0, width, height);
 	ssaoSProg->bind();
 	commonUbo.setBinding(0);
@@ -262,13 +255,13 @@ void Ssao::run()
 	for(U32 i = 0; i < blurringIterationsCount; i++)
 	{
 		// hpass
-		hblurFbo.bind(Fbo::FT_ALL, true);
+		hblurFbo.bind(true);
 		hblurSProg->bind();
 		hblurSProg->findUniformVariable("img").set(vblurFai);
 		r->drawQuad();
 
 		// vpass
-		vblurFbo.bind(Fbo::FT_ALL, true);
+		vblurFbo.bind(true);
 		vblurSProg->bind();
 		vblurSProg->findUniformVariable("img").set(hblurFai);
 		r->drawQuad();

+ 1 - 6
src/renderer/Tiler.cpp

@@ -233,12 +233,7 @@ void Tiler::initInternal(Renderer* r_)
 		GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT);
 	fai.setFiltering(Texture::TFT_NEAREST);
 
-	fbo.create();
-	fbo.setColorAttachments({&fai});
-	if(!fbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("FBO not complete");
-	}
+	fbo.create({{&fai, GL_COLOR_ATTACHMENT0}});
 
 	// Create PBO
 	pbo.create(GL_PIXEL_PACK_BUFFER, 

+ 8 - 3
src/util/FilePosix.cpp

@@ -7,6 +7,11 @@
 #include <dirent.h>
 #include <cerrno>
 
+// Define PATH_MAX if needed
+#ifndef PATH_MAX
+#	define PATH_MAX 4096
+#endif
+
 namespace anki {
 
 //==============================================================================
@@ -54,18 +59,18 @@ void removeDirectory(const char* dirname)
 	struct dirent* entry;
 	char path[PATH_MAX];
 
-	if(path == NULL) 
+	if(path == nullptr) 
 	{
 		throw ANKI_EXCEPTION("Out of memory error");
 	}
 
 	dir = opendir(dirname);
-	if(dir == NULL) 
+	if(dir == nullptr) 
 	{
 		throw ANKI_EXCEPTION("opendir() failed");
 	}
 
-	while((entry = readdir(dir)) != NULL) 
+	while((entry = readdir(dir)) != nullptr) 
 	{
 		if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) 
 		{