diff --git a/src/bitmap.cpp b/src/bitmap.cpp
index dfa3cb8..7815114 100644
--- a/src/bitmap.cpp
+++ b/src/bitmap.cpp
@@ -150,7 +150,7 @@ struct BitmapPrivate
 
 	void bindFBO()
 	{
-		FBO::bind(gl.fbo, FBO::Generic);
+		FBO::bind(gl.fbo);
 	}
 
 	void pushSetViewport(ShaderBase &shader) const
@@ -544,7 +544,7 @@ void Bitmap::blur()
 	glState.viewport.pushSet(IntRect(0, 0, width(), height()));
 
 	TEX::bind(p->gl.tex);
-	FBO::bind(auxTex.fbo, FBO::Generic);
+	FBO::bind(auxTex.fbo);
 
 	pass1.bind();
 	pass1.setTexSize(Vec2i(width(), height()));
@@ -625,7 +625,7 @@ void Bitmap::radialBlur(int angle, int divisions)
 
 	TEXFBO newTex = shState->texPool().request(_width, _height);
 
-	FBO::bind(newTex.fbo, FBO::Generic);
+	FBO::bind(newTex.fbo);
 
 	glState.clearColor.pushSet(Vec4());
 	FBO::clear();
@@ -698,7 +698,7 @@ Color Bitmap::getPixel(int x, int y) const
 	{
 		p->allocSurface();
 
-		FBO::bind(p->gl.fbo, FBO::Generic);
+		FBO::bind(p->gl.fbo);
 
 		glState.viewport.pushSet(IntRect(0, 0, width(), height()));
 
@@ -764,7 +764,7 @@ void Bitmap::hueChange(int hue)
 	shader.bind();
 	shader.setHueAdjust(hueAdj);
 
-	FBO::bind(newTex.fbo, FBO::Generic);
+	FBO::bind(newTex.fbo);
 	p->pushSetViewport(shader);
 	p->bindTexture(shader);
 
@@ -921,7 +921,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
 			GLMeta::blitBegin(p->gl);
 			GLMeta::blitSource(gpTF);
 			GLMeta::blitRectangle(IntRect(0, 0, txtSurf->w, txtSurf->h),
-			                      posRect, FBO::Linear);
+			                      posRect, true);
 			GLMeta::blitEnd();
 		}
 	}
diff --git a/src/gl-meta.cpp b/src/gl-meta.cpp
index 7779f71..e4df8c4 100644
--- a/src/gl-meta.cpp
+++ b/src/gl-meta.cpp
@@ -34,7 +34,10 @@ void subRectImageUpload(GLint srcW, GLint srcX, GLint srcY,
 {
 	if (gl.unpack_subimage)
 	{
-		PixelStore::setupSubImage(srcW, srcX, srcY);
+		gl.PixelStorei(GL_UNPACK_ROW_LENGTH, srcW);
+		gl.PixelStorei(GL_UNPACK_SKIP_PIXELS, srcX);
+		gl.PixelStorei(GL_UNPACK_SKIP_ROWS, srcY);
+
 		TEX::uploadSubImage(dstX, dstY, dstW, dstH, src->pixels, format);
 	}
 	else
@@ -55,7 +58,11 @@ void subRectImageUpload(GLint srcW, GLint srcX, GLint srcY,
 void subRectImageEnd()
 {
 	if (gl.unpack_subimage)
-		PixelStore::reset();
+	{
+		gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+		gl.PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+		gl.PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+	}
 }
 
 #define HAVE_NATIVE_VAO gl.GenVertexArrays
@@ -78,11 +85,11 @@ void vaoInit(VAO &vao, bool keepBound)
 {
 	if (HAVE_NATIVE_VAO)
 	{
-		vao.vao = ::VAO::gen();
-		::VAO::bind(vao.vao);
+		gl.GenVertexArrays(1, &vao.nativeVAO);
+		gl.BindVertexArray(vao.nativeVAO);
 		vaoBindRes(vao);
 		if (!keepBound)
-			::VAO::unbind();
+			gl.BindVertexArray(0);
 	}
 	else
 	{
@@ -97,13 +104,13 @@ void vaoInit(VAO &vao, bool keepBound)
 void vaoFini(VAO &vao)
 {
 	if (HAVE_NATIVE_VAO)
-		::VAO::del(vao.vao);
+		gl.DeleteVertexArrays(1, &vao.nativeVAO);
 }
 
 void vaoBind(VAO &vao)
 {
 	if (HAVE_NATIVE_VAO)
-		::VAO::bind(vao.vao);
+		gl.BindVertexArray(vao.nativeVAO);
 	else
 		vaoBindRes(vao);
 }
@@ -112,7 +119,7 @@ void vaoUnbind(VAO &vao)
 {
 	if (HAVE_NATIVE_VAO)
 	{
-		::VAO::unbind();
+		gl.BindVertexArray(0);
 	}
 	else
 	{
@@ -130,11 +137,11 @@ static void _blitBegin(FBO::ID fbo, const Vec2i &size)
 {
 	if (HAVE_NATIVE_BLIT)
 	{
-		FBO::bind(fbo, FBO::Draw);
+		gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo.gl);
 	}
 	else
 	{
-		FBO::bind(fbo, FBO::Generic);
+		FBO::bind(fbo);
 		glState.viewport.pushSet(IntRect(0, 0, size.x, size.y));
 
 		SimpleShader &shader = shState->shaders().simple;
@@ -158,7 +165,7 @@ void blitSource(TEXFBO &source)
 {
 	if (HAVE_NATIVE_BLIT)
 	{
-		FBO::bind(source.fbo, FBO::Read);
+		gl.BindFramebuffer(GL_READ_FRAMEBUFFER, source.fbo.gl);
 	}
 	else
 	{
@@ -168,29 +175,29 @@ void blitSource(TEXFBO &source)
 	}
 }
 
-void blitRectangle(const IntRect &src, const Vec2i &dstPos, FBO::BlitMode mode)
+void blitRectangle(const IntRect &src, const Vec2i &dstPos, bool smooth)
 {
-	blitRectangle(src, IntRect(dstPos.x, dstPos.y, src.w, src.h), mode);
+	blitRectangle(src, IntRect(dstPos.x, dstPos.y, src.w, src.h), smooth);
 }
 
-void blitRectangle(const IntRect &src, const IntRect &dst, FBO::BlitMode mode)
+void blitRectangle(const IntRect &src, const IntRect &dst, bool smooth)
 {
 	if (HAVE_NATIVE_BLIT)
 	{
-		FBO::blit(src.x, src.y, src.w, src.h,
-		          dst.x, dst.y, dst.w, dst.h,
-		          mode);
+		gl.BlitFramebuffer(src.x, src.y, src.x+src.w, src.y+src.h,
+		                   dst.x, dst.y, dst.x+dst.w, dst.y+dst.h,
+		                   GL_COLOR_BUFFER_BIT, smooth ? GL_LINEAR : GL_NEAREST);
 	}
 	else
 	{
-		if (mode == FBO::Linear)
+		if (smooth)
 			TEX::setSmooth(true);
 
 		Quad &quad = shState->gpQuad();
 		quad.setTexPosRect(src, dst);
 		quad.draw();
 
-		if (mode == FBO::Linear)
+		if (smooth)
 			TEX::setSmooth(false);
 	}
 }
diff --git a/src/gl-meta.h b/src/gl-meta.h
index 89b6512..ca683bc 100644
--- a/src/gl-meta.h
+++ b/src/gl-meta.h
@@ -48,7 +48,7 @@ struct VAO
 	IBO::ID ibo;
 
 	/* Don't touch */
-	::VAO::ID vao;
+	GLuint nativeVAO;
 };
 
 template<class VertexType>
@@ -69,9 +69,9 @@ void blitBegin(TEXFBO &target);
 void blitBeginScreen(const Vec2i &size);
 void blitSource(TEXFBO &source);
 void blitRectangle(const IntRect &src, const Vec2i &dstPos,
-                   FBO::BlitMode mode = FBO::Nearest);
+                   bool smooth = false);
 void blitRectangle(const IntRect &src, const IntRect &dst,
-                   FBO::BlitMode mode = FBO::Nearest);
+                   bool smooth = false);
 void blitEnd();
 
 }
diff --git a/src/gl-util.h b/src/gl-util.h
index c98f557..14dadb2 100644
--- a/src/gl-util.h
+++ b/src/gl-util.h
@@ -105,19 +105,6 @@ namespace FBO
 {
 	DEF_GL_ID
 
-	enum Mode
-	{
-		Draw = 0,
-		Read = 1,
-		Generic = 2
-	};
-
-	enum BlitMode
-	{
-		Nearest = 0,
-		Linear  = 1
-	};
-
 	inline ID gen()
 	{
 		ID id;
@@ -131,21 +118,14 @@ namespace FBO
 		gl.DeleteFramebuffers(1, &id.gl);
 	}
 
-	inline void bind(ID id, Mode mode)
+	inline void bind(ID id)
 	{
-		static const GLenum modes[] =
-		{
-			GL_DRAW_FRAMEBUFFER,
-			GL_READ_FRAMEBUFFER,
-			GL_FRAMEBUFFER
-		};
-
-		gl.BindFramebuffer(modes[mode], id.gl);
+		gl.BindFramebuffer(GL_FRAMEBUFFER, id.gl);
 	}
 
-	inline void unbind(Mode mode)
+	inline void unbind()
 	{
-		bind(ID(0), mode);
+		bind(ID(0));
 	}
 
 	inline void setTarget(TEX::ID target, unsigned colorAttach = 0)
@@ -153,66 +133,12 @@ namespace FBO
 		gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, target.gl, 0);
 	}
 
-	inline void blit(int srcX, int srcY,
-	                 int srcW, int srcH,
-	                 int dstX, int dstY,
-	                 int dstW, int dstH,
-	                 BlitMode mode = Nearest)
-	{
-		static const GLenum modes[] =
-		{
-			GL_NEAREST,
-			GL_LINEAR
-		};
-
-		gl.BlitFramebuffer(srcX, srcY, srcX+srcW, srcY+srcH,
-		                   dstX, dstY, dstX+dstW, dstY+dstH,
-		                   GL_COLOR_BUFFER_BIT, modes[mode]);
-	}
-
-	inline void blit(int srcX, int srcY,
-	                 int dstX, int dstY,
-	                 int srcW, int srcH,
-	                 BlitMode mode = Nearest)
-	{
-		blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH, mode);
-	}
-
 	inline void clear()
 	{
 		gl.Clear(GL_COLOR_BUFFER_BIT);
 	}
 }
 
-/* Vertex Array Object */
-namespace VAO
-{
-	DEF_GL_ID
-
-	inline ID gen()
-	{
-		ID id;
-		gl.GenVertexArrays(1, &id.gl);
-
-		return id;
-	}
-
-	inline void del(ID id)
-	{
-		gl.DeleteVertexArrays(1, &id.gl);
-	}
-
-	inline void bind(ID id)
-	{
-		gl.BindVertexArray(id.gl);
-	}
-
-	inline void unbind()
-	{
-		bind(ID(0));
-	}
-}
-
 template<GLenum target>
 struct GenericBO
 {
@@ -265,24 +191,6 @@ typedef struct GenericBO<GL_ELEMENT_ARRAY_BUFFER> IBO;
 
 #undef DEF_GL_ID
 
-namespace PixelStore
-{
-	/* Setup a 'glSubTexImage2D()' call where the uploaded image
-	 * itself is part of a bigger image in client memory */
-	inline void setupSubImage(GLint imgWidth, GLint subX, GLint subY)
-	{
-		gl.PixelStorei(GL_UNPACK_ROW_LENGTH, imgWidth);
-		gl.PixelStorei(GL_UNPACK_SKIP_PIXELS, subX);
-		gl.PixelStorei(GL_UNPACK_SKIP_ROWS, subY);
-	}
-
-	/* Reset all states set with 'setupSubImage()' */
-	inline void reset()
-	{
-		setupSubImage(0, 0, 0);
-	}
-}
-
 /* Convenience struct wrapping a framebuffer
  * and a 2D texture as its target */
 struct TEXFBO
@@ -319,7 +227,7 @@ struct TEXFBO
 
 	static inline void linkFBO(TEXFBO &obj)
 	{
-		FBO::bind(obj.fbo, FBO::Draw);
+		FBO::bind(obj.fbo);
 		FBO::setTarget(obj.tex);
 	}
 
diff --git a/src/graphics.cpp b/src/graphics.cpp
index f520cd2..c158521 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -107,7 +107,7 @@ struct PingPong
 private:
 	void bind()
 	{
-		FBO::bind(rt[dstInd].fbo, FBO::Generic);
+		FBO::bind(rt[dstInd].fbo);
 	}
 };
 
@@ -513,7 +513,7 @@ struct GraphicsPrivate
 	{
 		GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y),
 		                      IntRect(scOffset.x, scSize.y+scOffset.y, scSize.x, -scSize.y),
-		                      threadData->config.smoothScaling ? FBO::Linear : FBO::Nearest);
+		                      threadData->config.smoothScaling);
 	}
 
 	void redrawScreen()
@@ -652,14 +652,14 @@ void Graphics::transition(int duration,
 
 		/* Draw the composed frame to a buffer first
 		 * (we need this because we're skipping PingPong) */
-		FBO::bind(p->transBuffer.fbo, FBO::Generic);
+		FBO::bind(p->transBuffer.fbo);
 		FBO::clear();
 		p->screenQuad.draw();
 
 		p->checkResize();
 
 		/* Then blit it flipped and scaled to the screen */
-		FBO::unbind(FBO::Generic);
+		FBO::unbind();
 		FBO::clear();
 
 		GLMeta::blitBeginScreen(Vec2i(p->winSize));
@@ -716,7 +716,7 @@ void Graphics::wait(int duration)
 
 void Graphics::fadeout(int duration)
 {
-	FBO::unbind(FBO::Generic);
+	FBO::unbind();
 
 	for (int i = duration-1; i > -1; --i)
 	{
@@ -743,7 +743,7 @@ void Graphics::fadeout(int duration)
 
 void Graphics::fadein(int duration)
 {
-	FBO::unbind(FBO::Generic);
+	FBO::unbind();
 
 	for (int i = 0; i < duration; ++i)
 	{
diff --git a/src/tilemap.cpp b/src/tilemap.cpp
index 16832c4..8f9bf0c 100644
--- a/src/tilemap.cpp
+++ b/src/tilemap.cpp
@@ -551,7 +551,7 @@ struct TilemapPrivate
 		TileAtlas::BlitVec blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
 
 		/* Clear atlas */
-		FBO::bind(atlas.gl.fbo, FBO::Generic);
+		FBO::bind(atlas.gl.fbo);
 		glState.clearColor.pushSet(Vec4());
 		glState.scissorTest.pushSet(false);
 
diff --git a/src/window.cpp b/src/window.cpp
index 0a29518..105ebef 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -416,7 +416,7 @@ struct WindowPrivate
 		TEX::allocEmpty(baseTex.width, baseTex.height);
 		TEX::unbind();
 
-		FBO::bind(baseTex.fbo, FBO::Generic);
+		FBO::bind(baseTex.fbo);
 		glState.viewport.pushSet(IntRect(0, 0, baseTex.width, baseTex.height));
 		glState.clearColor.pushSet(Vec4());