Fix texture upload and internalformat handling.

We weren't handling several of the format/type/internalformat combos
from table 3.2 of the OpenGL ES 3.0.5 spec. In particular those where
the format/type of a glTexSubImage2D() call can be used to update
images with an internal format not directly corresponding to it. Some
of these cases were handled using the blitter, but not all GL formats
have a SwiftShader equivalent. Also, the blitter is slower than
specialized C++ pixel transfer code, and the blitter's fallback path is
even slower.

This patch provides specialized pixel rectangle transfer code for each
combination of formats. We also now only store the effective sized
internal format of the images. Validation also happens using the sized
internal format wherever feasible, instead of unsized formats or
SwiftShader formats.

Change-Id: Id55db490002ab8fc2f16f766c43b43f121e5768e
Reviewed-on: https://swiftshader-review.googlesource.com/17429
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp
index ef5e93b..49de8d7 100644
--- a/src/OpenGL/common/Image.cpp
+++ b/src/OpenGL/common/Image.cpp
@@ -14,7 +14,6 @@
 
 #include "Image.hpp"
 
-#include "../libEGL/Context.hpp"
 #include "../libEGL/Texture.hpp"
 #include "../common/debug.h"
 #include "Common/Math.hpp"
@@ -23,361 +22,11 @@
 #include <GLES3/gl3.h>
 
 #include <string.h>
+#include <algorithm>
 
-namespace
+namespace gl
 {
-	int getNumBlocks(int w, int h, int blockSizeX, int blockSizeY)
-	{
-		return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY);
-	}
-
-	enum DataType
-	{
-		Bytes_1,
-		Bytes_2,
-		Bytes_4,
-		Bytes_8,
-		Bytes_16,
-		ByteRGB,
-		UByteRGB,
-		ShortRGB,
-		UShortRGB,
-		IntRGB,
-		UIntRGB,
-		FloatRGB,
-		HalfFloatRGB,
-		RGBA4444,
-		RGBA5551,
-		R11G11B10F,
-		RGB9E5,
-		D16,
-		D24,
-		D32,
-		D32F,
-		D32FS8,
-		S8,
-		S24_8,
-	};
-
-	template<DataType dataType>
-	void LoadImageRow(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		UNIMPLEMENTED();
-	}
-
-	template<>
-	void LoadImageRow<Bytes_1>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		memcpy(dest, source, width);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_2>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		memcpy(dest, source, width * 2);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_4>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		memcpy(dest, source, width * 4);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_8>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		memcpy(dest, source, width * 8);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_16>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		memcpy(dest, source, width * 16);
-	}
-
-	template<>
-	void LoadImageRow<ByteRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		unsigned char *destB = dest;
-
-		for(int x = 0; x < width; x++)
-		{
-			destB[4 * x + 0] = source[x * 3 + 0];
-			destB[4 * x + 1] = source[x * 3 + 1];
-			destB[4 * x + 2] = source[x * 3 + 2];
-			destB[4 * x + 3] = 0x7F;
-		}
-	}
-
-	template<>
-	void LoadImageRow<UByteRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		unsigned char *destB = dest;
-
-		for(int x = 0; x < width; x++)
-		{
-			destB[4 * x + 0] = source[x * 3 + 0];
-			destB[4 * x + 1] = source[x * 3 + 1];
-			destB[4 * x + 2] = source[x * 3 + 2];
-			destB[4 * x + 3] = 0xFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<ShortRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned short *sourceS = reinterpret_cast<const unsigned short*>(source);
-		unsigned short *destS = reinterpret_cast<unsigned short*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destS[4 * x + 0] = sourceS[x * 3 + 0];
-			destS[4 * x + 1] = sourceS[x * 3 + 1];
-			destS[4 * x + 2] = sourceS[x * 3 + 2];
-			destS[4 * x + 3] = 0x7FFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<UShortRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned short *sourceS = reinterpret_cast<const unsigned short*>(source);
-		unsigned short *destS = reinterpret_cast<unsigned short*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destS[4 * x + 0] = sourceS[x * 3 + 0];
-			destS[4 * x + 1] = sourceS[x * 3 + 1];
-			destS[4 * x + 2] = sourceS[x * 3 + 2];
-			destS[4 * x + 3] = 0xFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<IntRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
-		unsigned int *destI = reinterpret_cast<unsigned int*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[4 * x + 0] = sourceI[x * 3 + 0];
-			destI[4 * x + 1] = sourceI[x * 3 + 1];
-			destI[4 * x + 2] = sourceI[x * 3 + 2];
-			destI[4 * x + 3] = 0x7FFFFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<UIntRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
-		unsigned int *destI = reinterpret_cast<unsigned int*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[4 * x + 0] = sourceI[x * 3 + 0];
-			destI[4 * x + 1] = sourceI[x * 3 + 1];
-			destI[4 * x + 2] = sourceI[x * 3 + 2];
-			destI[4 * x + 3] = 0xFFFFFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<FloatRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const float *sourceF = reinterpret_cast<const float*>(source);
-		float *destF = reinterpret_cast<float*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[4 * x + 0] = sourceF[x * 3 + 0];
-			destF[4 * x + 1] = sourceF[x * 3 + 1];
-			destF[4 * x + 2] = sourceF[x * 3 + 2];
-			destF[4 * x + 3] = 1.0f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<HalfFloatRGB>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
-		unsigned short *destH = reinterpret_cast<unsigned short*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destH[4 * x + 0] = sourceH[x * 3 + 0];
-			destH[4 * x + 1] = sourceH[x * 3 + 1];
-			destH[4 * x + 2] = sourceH[x * 3 + 2];
-			destH[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGBA4444>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned short *source4444 = reinterpret_cast<const unsigned short*>(source);
-		unsigned char *dest4444 = dest;
-
-		for(int x = 0; x < width; x++)
-		{
-			unsigned short rgba = source4444[x];
-			dest4444[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
-			dest4444[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
-			dest4444[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
-			dest4444[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGBA5551>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned short *source5551 = reinterpret_cast<const unsigned short*>(source);
-		unsigned char *dest5551 = dest;
-
-		for(int x = 0; x < width; x++)
-		{
-			unsigned short rgba = source5551[x];
-			dest5551[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
-			dest5551[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
-			dest5551[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
-			dest5551[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
-		}
-	}
-
-	template<>
-	void LoadImageRow<R11G11B10F>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const sw::R11G11B10F *sourceRGB = reinterpret_cast<const sw::R11G11B10F*>(source);
-		sw::half *destF = reinterpret_cast<sw::half*>(dest);
-
-		for(int x = 0; x < width; x++, sourceRGB++, destF+=4)
-		{
-			sourceRGB->toRGB16F(destF);
-			destF[3] = 1.0f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGB9E5>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const sw::RGB9E5 *sourceRGB = reinterpret_cast<const sw::RGB9E5*>(source);
-		sw::half *destF = reinterpret_cast<sw::half*>(dest);
-
-		for(int x = 0; x < width; x++, sourceRGB++, destF += 4)
-		{
-			sourceRGB->toRGB16F(destF);
-			destF[3] = 1.0f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<D16>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
-		float *destF = reinterpret_cast<float*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = (float)sourceD16[x] / 0xFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<D24>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned int *sourceD24 = reinterpret_cast<const unsigned int*>(source);
-		float *destF = reinterpret_cast<float*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = (float)(sourceD24[x] & 0xFFFFFF00) / 0xFFFFFF00;
-		}
-	}
-
-	template<>
-	void LoadImageRow<D32>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned int *sourceD32 = reinterpret_cast<const unsigned int*>(source);
-		float *destF = reinterpret_cast<float*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = (float)sourceD32[x] / 0xFFFFFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<S8>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
-		unsigned char *destI = dest;
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[x] = static_cast<unsigned char>(sourceI[x] & 0x000000FF);   // FIXME: Quad layout
-		}
-	}
-
-	template<>
-	void LoadImageRow<D32F>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		const float *sourceF = reinterpret_cast<const float*>(source);
-		float *destF = reinterpret_cast<float*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = sw::clamp(sourceF[x], 0.0f, 1.0f);
-		}
-	}
-
-	template<>
-	void LoadImageRow<D32FS8>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
-		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
-		float *destF = reinterpret_cast<float*>(dest);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = sw::clamp(sourceD32FS8[x].depth32f, 0.0f, 1.0f);
-		}
-	}
-
-	template<>
-	void LoadImageRow<S24_8>(const unsigned char *source, unsigned char *dest, GLsizei width)
-	{
-		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
-		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
-		unsigned char *destI = dest;
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[x] = static_cast<unsigned char>(sourceD32FS8[x].stencil24_8 & 0x000000FF);   // FIXME: Quad layout
-		}
-	}
-
-	template<DataType dataType>
-	void LoadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, int destPitch, GLsizei destSlice, const void *input, void *buffer)
-	{
-		for(int z = 0; z < depth; z++)
-		{
-			const unsigned char *inputStart = static_cast<const unsigned char*>(input) + (z * inputPitch * inputHeight);
-			unsigned char *destStart = static_cast<unsigned char*>(buffer) + (z * destSlice);
-			for(int y = 0; y < height; y++)
-			{
-				const unsigned char *source = inputStart + y * inputPitch;
-				unsigned char *dest = destStart + y * destPitch;
-
-				LoadImageRow<dataType>(source, dest, width);
-			}
-		}
-	}
-}
-
-namespace egl
-{
-	sw::Format ConvertFormatType(GLenum format, GLenum type)
+	sw::Format ConvertReadFormatType(GLenum format, GLenum type)
 	{
 		switch(format)
 		{
@@ -391,12 +40,6 @@
 			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_LUMINANCE8_EXT:
-			return sw::FORMAT_L8;
-		case GL_LUMINANCE16F_EXT:
-			return sw::FORMAT_L16F;
-		case GL_LUMINANCE32F_EXT:
-			return sw::FORMAT_L32F;
 		case GL_LUMINANCE_ALPHA:
 			switch(type)
 			{
@@ -407,12 +50,6 @@
 			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_LUMINANCE8_ALPHA8_EXT:
-			return sw::FORMAT_A8L8;
-		case GL_LUMINANCE_ALPHA16F_EXT:
-			return sw::FORMAT_A16L16F;
-		case GL_LUMINANCE_ALPHA32F_EXT:
-			return sw::FORMAT_A32L32F;
 		case GL_RGBA:
 			switch(type)
 			{
@@ -422,11 +59,11 @@
 			case GL_HALF_FLOAT:             return sw::FORMAT_A16B16G16R16F;
 			case GL_HALF_FLOAT_OES:         return sw::FORMAT_A16B16G16R16F;
 			case GL_FLOAT:                  return sw::FORMAT_A32B32G32R32F;
+			case GL_UNSIGNED_INT_2_10_10_10_REV_EXT: return sw::FORMAT_A2B10G10R10;
 			default: UNREACHABLE(type);
 			}
 			break;
 		case GL_BGRA_EXT:
-		case GL_BGRA8_EXT:
 			switch(type)
 			{
 			case GL_UNSIGNED_BYTE:                  return sw::FORMAT_A8R8G8B8;
@@ -476,12 +113,6 @@
 			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_ALPHA8_EXT:
-			return sw::FORMAT_A8;
-		case GL_ALPHA16F_EXT:
-			return sw::FORMAT_A16F;
-		case GL_ALPHA32F_EXT:
-			return sw::FORMAT_A32F;
 		case GL_RED_INTEGER:
 			switch(type)
 			{
@@ -498,6 +129,14 @@
 			default: UNREACHABLE(type);
 			}
 			break;
+		case GL_RGB_INTEGER:
+			switch(type)
+			{
+			case GL_INT:          return sw::FORMAT_X32B32G32R32I;
+			case GL_UNSIGNED_INT: return sw::FORMAT_X32B32G32R32UI;
+			default: UNREACHABLE(type);
+			}
+			break;
 		case GL_RGBA_INTEGER:
 			switch(type)
 			{
@@ -519,384 +158,407 @@
 			break;
 		default:
 			UNREACHABLE(format);
+			break;
 		}
 
 		return sw::FORMAT_NULL;
 	}
 
-	sw::Format SelectInternalFormat(GLenum format, GLenum type)
+	bool IsUnsizedInternalFormat(GLint internalformat)
 	{
-		switch(format)
+		switch(internalformat)
 		{
-		case GL_ETC1_RGB8_OES:
-			return sw::FORMAT_ETC1;
-		case GL_COMPRESSED_R11_EAC:
-			return sw::FORMAT_R11_EAC;
-		case GL_COMPRESSED_SIGNED_R11_EAC:
-			return sw::FORMAT_SIGNED_R11_EAC;
-		case GL_COMPRESSED_RG11_EAC:
-			return sw::FORMAT_RG11_EAC;
-		case GL_COMPRESSED_SIGNED_RG11_EAC:
-			return sw::FORMAT_SIGNED_RG11_EAC;
-		case GL_COMPRESSED_RGB8_ETC2:
-			return sw::FORMAT_RGB8_ETC2;
-		case GL_COMPRESSED_SRGB8_ETC2:
-			return sw::FORMAT_SRGB8_ETC2;
-		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-			return sw::FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-			return sw::FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-		case GL_COMPRESSED_RGBA8_ETC2_EAC:
-			return sw::FORMAT_RGBA8_ETC2_EAC;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-			return sw::FORMAT_SRGB8_ALPHA8_ETC2_EAC;
-		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
-			return sw::FORMAT_RGBA_ASTC_4x4_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
-			return sw::FORMAT_RGBA_ASTC_5x4_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_5x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_6x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
-			return sw::FORMAT_RGBA_ASTC_6x6_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_8x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
-			return sw::FORMAT_RGBA_ASTC_8x6_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
-			return sw::FORMAT_RGBA_ASTC_8x8_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x6_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x8_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x10_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
-			return sw::FORMAT_RGBA_ASTC_12x10_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
-			return sw::FORMAT_RGBA_ASTC_12x12_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR;
-		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-			return sw::FORMAT_DXT1;
-		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-			return sw::FORMAT_DXT3;
-		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-			return sw::FORMAT_DXT5;
+		case GL_ALPHA:
+		case GL_LUMINANCE:
+		case GL_LUMINANCE_ALPHA:
+		case GL_RED:
+		case GL_RG:
+		case GL_RGB:
+		case GL_RGBA:
+		case GL_RED_INTEGER:
+		case GL_RG_INTEGER:
+		case GL_RGB_INTEGER:
+		case GL_RGBA_INTEGER:
+		case GL_BGRA_EXT:
+		case GL_DEPTH_COMPONENT:
+		case GL_DEPTH_STENCIL:
+		// GL_EXT_sRGB
+	//	case GL_SRGB_EXT:
+	//	case GL_SRGB_ALPHA_EXT:
+			return true;
 		default:
+			return false;
+		}
+	}
+
+	GLenum GetBaseInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		// [OpenGL ES 3.0 Table 3.13]
+		case GL_R8:       return GL_RED;
+		case GL_R8_SNORM: return GL_RED;
+		case GL_RG8:       return GL_RG;
+		case GL_RG8_SNORM: return GL_RG;
+		case GL_RGB8:       return GL_RGB;
+		case GL_RGB8_SNORM: return GL_RGB;
+		case GL_RGB565:     return GL_RGB;
+		case GL_RGBA4:        return GL_RGBA;
+		case GL_RGB5_A1:      return GL_RGBA;
+		case GL_RGBA8:        return GL_RGBA;
+		case GL_RGBA8_SNORM:  return GL_RGBA;
+		case GL_RGB10_A2:     return GL_RGBA;
+		case GL_RGB10_A2UI:   return GL_RGBA;
+		case GL_SRGB8:        return GL_RGB;
+		case GL_SRGB8_ALPHA8: return GL_RGBA;
+		case GL_R16F:    return GL_RED;
+		case GL_RG16F:   return GL_RG;
+		case GL_RGB16F:  return GL_RGB;
+		case GL_RGBA16F: return GL_RGBA;
+		case GL_R32F:    return GL_RED;
+		case GL_RG32F:   return GL_RG;
+		case GL_RGB32F:  return GL_RGB;
+		case GL_RGBA32F: return GL_RGBA;
+		case GL_R11F_G11F_B10F: return GL_RGB;
+		case GL_RGB9_E5:        return GL_RGB;
+		case GL_R8I:      return GL_RED;
+		case GL_R8UI:     return GL_RED;
+		case GL_R16I:     return GL_RED;
+		case GL_R16UI:    return GL_RED;
+		case GL_R32I:     return GL_RED;
+		case GL_R32UI:    return GL_RED;
+		case GL_RG8I:     return GL_RG;
+		case GL_RG8UI:    return GL_RG;
+		case GL_RG16I:    return GL_RG;
+		case GL_RG16UI:   return GL_RG;
+		case GL_RG32I:    return GL_RG;
+		case GL_RG32UI:   return GL_RG;
+		case GL_RGB8I:    return GL_RGB;
+		case GL_RGB8UI:   return GL_RGB;
+		case GL_RGB16I:   return GL_RGB;
+		case GL_RGB16UI:  return GL_RGB;
+		case GL_RGB32I:   return GL_RGB;
+		case GL_RGB32UI:  return GL_RGB;
+		case GL_RGBA8I:   return GL_RGBA;
+		case GL_RGBA8UI:  return GL_RGBA;
+		case GL_RGBA16I:  return GL_RGBA;
+		case GL_RGBA16UI: return GL_RGBA;
+		case GL_RGBA32I:  return GL_RGBA;
+		case GL_RGBA32UI: return GL_RGBA;
+
+		// GL_EXT_texture_storage
+		case GL_ALPHA8_EXT:            return GL_ALPHA;
+		case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA;
+		case GL_LUMINANCE8_EXT:        return GL_LUMINANCE;
+
+		case GL_BGRA8_EXT: return GL_BGRA_EXT;   // GL_APPLE_texture_format_BGRA8888
+
+		case GL_DEPTH_COMPONENT24:     return GL_DEPTH_COMPONENT;
+		case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT;
+		case GL_DEPTH_COMPONENT32F:    return GL_DEPTH_COMPONENT;
+		case GL_DEPTH_COMPONENT16:     return GL_DEPTH_COMPONENT;
+		case GL_DEPTH32F_STENCIL8:     return GL_DEPTH_STENCIL;
+		case GL_DEPTH24_STENCIL8:      return GL_DEPTH_STENCIL;
+		case GL_STENCIL_INDEX8:        return GL_STENCIL_INDEX_OES;
+		default:
+			UNREACHABLE(internalformat);
 			break;
 		}
 
-		switch(type)
+		return GL_NONE;
+	}
+
+	GLint GetSizedInternalFormat(GLint internalformat, GLenum type)
+	{
+		if(!IsUnsizedInternalFormat(internalformat))
 		{
-		case GL_FLOAT:
-			switch(format)
-			{
-			case GL_ALPHA:
-			case GL_ALPHA32F_EXT:
-				return sw::FORMAT_A32F;
-			case GL_LUMINANCE:
-			case GL_LUMINANCE32F_EXT:
-				return sw::FORMAT_L32F;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE_ALPHA32F_EXT:
-				return sw::FORMAT_A32L32F;
-			case GL_RED:
-			case GL_R32F:
-				return sw::FORMAT_R32F;
-			case GL_RG:
-			case GL_RG32F:
-				return sw::FORMAT_G32R32F;
-			case GL_RGB:
-			case GL_RGB32F:
-				return sw::FORMAT_X32B32G32R32F;
-			case GL_R11F_G11F_B10F:
-			case GL_RGB9_E5:
-				return sw::FORMAT_X16B16G16R16F_UNSIGNED;
-			case GL_RGBA:
-			case GL_RGBA32F:
-				return sw::FORMAT_A32B32G32R32F;
-			case GL_R16F:
-				return sw::FORMAT_R16F;
-			case GL_RG16F:
-				return sw::FORMAT_G16R16F;
-			case GL_RGB16F:
-				return sw::FORMAT_X16B16G16R16F;
-			case GL_RGBA16F:
-				return sw::FORMAT_A16B16G16R16F;
-			case GL_DEPTH_COMPONENT:
-			case GL_DEPTH_COMPONENT32F:
-				return sw::FORMAT_D32F;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_HALF_FLOAT:
-		case GL_HALF_FLOAT_OES:
-			switch(format)
-			{
-			case GL_ALPHA:
-			case GL_ALPHA16F_EXT:
-				return sw::FORMAT_A16F;
-			case GL_LUMINANCE:
-			case GL_LUMINANCE16F_EXT:
-				return sw::FORMAT_L16F;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE_ALPHA16F_EXT:
-				return sw::FORMAT_A16L16F;
-			case GL_RED:
-			case GL_R16F:
-				return sw::FORMAT_R16F;
-			case GL_RG:
-			case GL_RG16F:
-				return sw::FORMAT_G16R16F;
-			case GL_RGBA:
-			case GL_RGBA16F:
-				return sw::FORMAT_A16B16G16R16F;
-			case GL_RGB:
-			case GL_RGB16F:
-				return sw::FORMAT_X16B16G16R16F;
-			case GL_R11F_G11F_B10F:
-			case GL_RGB9_E5:
-				return sw::FORMAT_X16B16G16R16F_UNSIGNED;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_BYTE:
-			switch(format)
-			{
-			case GL_R8_SNORM:
-			case GL_R8:
-			case GL_RED:
-				return sw::FORMAT_R8_SNORM;
-			case GL_R8I:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R8I;
-			case GL_RG8_SNORM:
-			case GL_RG8:
-			case GL_RG:
-				return sw::FORMAT_G8R8_SNORM;
-			case GL_RG8I:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G8R8I;
-			case GL_RGB8_SNORM:
-			case GL_RGB8:
-			case GL_RGB:
-				return sw::FORMAT_X8B8G8R8_SNORM;
-			case GL_RGB8I:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X8B8G8R8I;
-			case GL_RGBA8_SNORM:
-			case GL_RGBA8:
-			case GL_RGBA:
-				return sw::FORMAT_A8B8G8R8_SNORM;
-			case GL_RGBA8I:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A8B8G8R8I;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_BYTE:
-			switch(format)
-			{
-			case GL_LUMINANCE:
-			case GL_LUMINANCE8_EXT:
-				return sw::FORMAT_L8;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE8_ALPHA8_EXT:
-				return sw::FORMAT_A8L8;
-			case GL_R8_SNORM:
-				return sw::FORMAT_R8_SNORM;
-			case GL_R8:
-			case GL_RED:
-				return sw::FORMAT_R8;
-			case GL_R8UI:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R8UI;
-			case GL_RG8_SNORM:
-			case GL_RG8:
-			case GL_RG:
-				return sw::FORMAT_G8R8;
-			case GL_RG8UI:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G8R8UI;
-			case GL_RGB8_SNORM:
-			case GL_RGB8:
-			case GL_RGB:
-				return sw::FORMAT_X8B8G8R8;
-			case GL_SRGB8:
-				return sw::FORMAT_SRGB8_X8;
-			case GL_RGB8UI:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X8B8G8R8UI;
-			case GL_RGBA8_SNORM:
-			case GL_RGBA8:
-			case GL_RGBA:
-				return sw::FORMAT_A8B8G8R8;
-			case GL_SRGB8_ALPHA8:
-				return sw::FORMAT_SRGB8_A8;
-			case GL_RGBA8UI:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A8B8G8R8UI;
-			case GL_BGRA_EXT:
-			case GL_BGRA8_EXT:
-				return sw::FORMAT_A8R8G8B8;
-			case GL_ALPHA:
-			case GL_ALPHA8_EXT:
-				return sw::FORMAT_A8;
-			case SW_YV12_BT601:
-				return sw::FORMAT_YV12_BT601;
-			case SW_YV12_BT709:
-				return sw::FORMAT_YV12_BT709;
-			case SW_YV12_JFIF:
-				return sw::FORMAT_YV12_JFIF;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_SHORT:
-			switch(format)
-			{
-			case GL_R16I:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R16I;
-			case GL_RG16I:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G16R16I;
-			case GL_RGB16I:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X16B16G16R16I;
-			case GL_RGBA16I:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A16B16G16R16I;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_SHORT:
-			switch(format)
-			{
-			case GL_R16UI:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R16UI;
-			case GL_RG16UI:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G16R16UI;
-			case GL_RGB16UI:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X16B16G16R16UI;
-			case GL_RGBA16UI:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A16B16G16R16UI;
-			case GL_DEPTH_COMPONENT:
-			case GL_DEPTH_COMPONENT16:
-				return sw::FORMAT_D32F_LOCKABLE;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_INT:
-			switch(format)
-			{
-			case GL_RED_INTEGER:
-			case GL_R32I:
-				return sw::FORMAT_R32I;
-			case GL_RG_INTEGER:
-			case GL_RG32I:
-				return sw::FORMAT_G32R32I;
-			case GL_RGB_INTEGER:
-			case GL_RGB32I:
-				return sw::FORMAT_X32B32G32R32I;
-			case GL_RGBA_INTEGER:
-			case GL_RGBA32I:
-				return sw::FORMAT_A32B32G32R32I;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_INT:
-			switch(format)
-			{
-			case GL_RED_INTEGER:
-			case GL_R32UI:
-				return sw::FORMAT_R32UI;
-			case GL_RG_INTEGER:
-			case GL_RG32UI:
-				return sw::FORMAT_G32R32UI;
-			case GL_RGB_INTEGER:
-			case GL_RGB32UI:
-				return sw::FORMAT_X32B32G32R32UI;
-			case GL_RGBA_INTEGER:
-			case GL_RGBA32UI:
-				return sw::FORMAT_A32B32G32R32UI;
-			case GL_DEPTH_COMPONENT:
-			case GL_DEPTH_COMPONENT16:
-			case GL_DEPTH_COMPONENT24:
-			case GL_DEPTH_COMPONENT32_OES:
-				return sw::FORMAT_D32F_LOCKABLE;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_INT_24_8_OES:
-			if(format == GL_DEPTH_STENCIL || format == GL_DEPTH24_STENCIL8)
-			{
-				return sw::FORMAT_D32FS8_TEXTURE;
-			}
-			else UNREACHABLE(format);
-		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-			if(format == GL_DEPTH_STENCIL || format == GL_DEPTH32F_STENCIL8)
-			{
-				return sw::FORMAT_D32FS8_TEXTURE;
-			}
-			else UNREACHABLE(format);
-		case GL_UNSIGNED_SHORT_4_4_4_4:
-			return sw::FORMAT_A8R8G8B8;
-		case GL_UNSIGNED_SHORT_5_5_5_1:
-			return sw::FORMAT_A8R8G8B8;
-		case GL_UNSIGNED_SHORT_5_6_5:
-			return sw::FORMAT_R5G6B5;
-		case GL_UNSIGNED_INT_2_10_10_10_REV:
-			if(format == GL_RGB10_A2UI)
-			{
-				return sw::FORMAT_A2B10G10R10UI;
-			}
-			else
-			{
-				return sw::FORMAT_A2B10G10R10;
-			}
-		case GL_UNSIGNED_INT_10F_11F_11F_REV:
-		case GL_UNSIGNED_INT_5_9_9_9_REV:   // 5 is the exponent field, not alpha.
-			return sw::FORMAT_X16B16G16R16F_UNSIGNED;
-		default:
-			UNREACHABLE(type);
+			return internalformat;
 		}
 
-		return sw::FORMAT_NULL;
+		switch(internalformat)
+		{
+		case GL_RGBA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE: return GL_RGBA8;
+			case GL_BYTE:          return GL_RGBA8_SNORM;
+			case GL_UNSIGNED_SHORT_4_4_4_4:      return GL_RGBA4;
+			case GL_UNSIGNED_SHORT_5_5_5_1:      return GL_RGB5_A1;
+			case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2;
+			case GL_FLOAT:          return GL_RGBA32F;
+			case GL_HALF_FLOAT:     return GL_RGBA16F;
+			case GL_HALF_FLOAT_OES: return GL_RGBA16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RGBA_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RGBA8UI;
+			case GL_BYTE:           return GL_RGBA8I;
+			case GL_UNSIGNED_SHORT: return GL_RGBA16UI;
+			case GL_SHORT:          return GL_RGBA16I;
+			case GL_UNSIGNED_INT:   return GL_RGBA32UI;
+			case GL_INT:            return GL_RGBA32I;
+			case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2UI;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RGB:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RGB8;
+			case GL_BYTE:           return GL_RGB8_SNORM;
+			case GL_UNSIGNED_SHORT_5_6_5:         return GL_RGB565;
+			case GL_UNSIGNED_INT_10F_11F_11F_REV: return GL_R11F_G11F_B10F;
+			case GL_UNSIGNED_INT_5_9_9_9_REV:     return GL_RGB9_E5;
+			case GL_FLOAT:          return GL_RGB32F;
+			case GL_HALF_FLOAT:     return GL_RGB16F;
+			case GL_HALF_FLOAT_OES: return GL_RGB16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RGB_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RGB8UI;
+			case GL_BYTE:           return GL_RGB8I;
+			case GL_UNSIGNED_SHORT: return GL_RGB16UI;
+			case GL_SHORT:          return GL_RGB16I;
+			case GL_UNSIGNED_INT:   return GL_RGB32UI;
+			case GL_INT:            return GL_RGB32I;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RG:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RG8;
+			case GL_BYTE:           return GL_RG8_SNORM;
+			case GL_FLOAT:          return GL_RG32F;
+			case GL_HALF_FLOAT:     return GL_RG16F;
+			case GL_HALF_FLOAT_OES: return GL_RG16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RG_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RG8UI;
+			case GL_BYTE:           return GL_RG8I;
+			case GL_UNSIGNED_SHORT: return GL_RG16UI;
+			case GL_SHORT:          return GL_RG16I;
+			case GL_UNSIGNED_INT:   return GL_RG32UI;
+			case GL_INT:            return GL_RG32I;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RED:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_R8;
+			case GL_BYTE:           return GL_R8_SNORM;
+			case GL_FLOAT:          return GL_R32F;
+			case GL_HALF_FLOAT:     return GL_R16F;
+			case GL_HALF_FLOAT_OES: return GL_R16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RED_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_R8UI;
+			case GL_BYTE:           return GL_R8I;
+			case GL_UNSIGNED_SHORT: return GL_R16UI;
+			case GL_SHORT:          return GL_R16I;
+			case GL_UNSIGNED_INT:   return GL_R32UI;
+			case GL_INT:            return GL_R32I;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_LUMINANCE8_ALPHA8_EXT;
+			case GL_FLOAT:          return GL_LUMINANCE_ALPHA32F_EXT;
+			case GL_HALF_FLOAT:     return GL_LUMINANCE_ALPHA16F_EXT;
+			case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_LUMINANCE8_EXT;
+			case GL_FLOAT:          return GL_LUMINANCE32F_EXT;
+			case GL_HALF_FLOAT:     return GL_LUMINANCE16F_EXT;
+			case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_ALPHA8_EXT;
+			case GL_FLOAT:          return GL_ALPHA32F_EXT;
+			case GL_HALF_FLOAT:     return GL_ALPHA16F_EXT;
+			case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_BGRA_EXT:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:                  return GL_BGRA8_EXT;
+			case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: // Only valid for glReadPixels calls.
+			case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: // Only valid for glReadPixels calls.
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_DEPTH_COMPONENT:
+			switch(type)
+			{
+			case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16;
+			case GL_UNSIGNED_INT:   return GL_DEPTH_COMPONENT32_OES;
+			case GL_FLOAT:          return GL_DEPTH_COMPONENT32F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_DEPTH_STENCIL:
+			switch(type)
+			{
+			case GL_UNSIGNED_INT_24_8:              return GL_DEPTH24_STENCIL8;
+			case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return GL_DEPTH32F_STENCIL8;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+
+		// GL_OES_texture_stencil8
+	//	case GL_STENCIL_INDEX_OES / GL_UNSIGNED_BYTE: return GL_STENCIL_INDEX8;
+
+		// GL_EXT_sRGB
+	//	case GL_SRGB_EXT / GL_UNSIGNED_BYTE: return GL_SRGB8;
+	//	case GL_SRGB_ALPHA_EXT / GL_UNSIGNED_BYTE: return GL_SRGB8_ALPHA8;
+
+		default:
+			UNREACHABLE(internalformat);
+		}
+
+		return GL_NONE;
+	}
+
+	sw::Format SelectInternalFormat(GLint format)
+	{
+		switch(format)
+		{
+		case GL_RGBA4:   return sw::FORMAT_A8B8G8R8;
+		case GL_RGB5_A1: return sw::FORMAT_A8B8G8R8;
+		case GL_RGBA8:   return sw::FORMAT_A8B8G8R8;
+		case GL_RGB565:  return sw::FORMAT_R5G6B5;
+		case GL_RGB8:    return sw::FORMAT_X8B8G8R8;
+
+		case GL_DEPTH_COMPONENT32F:    return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH_COMPONENT16:     return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH_COMPONENT24:     return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH_COMPONENT32_OES: return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH24_STENCIL8:      return sw::FORMAT_D32FS8_TEXTURE;
+		case GL_DEPTH32F_STENCIL8:     return sw::FORMAT_D32FS8_TEXTURE;
+		case GL_STENCIL_INDEX8:        return sw::FORMAT_S8;
+
+		case GL_R8:             return sw::FORMAT_R8;
+		case GL_RG8:            return sw::FORMAT_G8R8;
+		case GL_R8I:            return sw::FORMAT_R8I;
+		case GL_RG8I:           return sw::FORMAT_G8R8I;
+		case GL_RGB8I:          return sw::FORMAT_X8B8G8R8I;
+		case GL_RGBA8I:         return sw::FORMAT_A8B8G8R8I;
+		case GL_R8UI:           return sw::FORMAT_R8UI;
+		case GL_RG8UI:          return sw::FORMAT_G8R8UI;
+		case GL_RGB8UI:         return sw::FORMAT_X8B8G8R8UI;
+		case GL_RGBA8UI:        return sw::FORMAT_A8B8G8R8UI;
+		case GL_R16I:           return sw::FORMAT_R16I;
+		case GL_RG16I:          return sw::FORMAT_G16R16I;
+		case GL_RGB16I:         return sw::FORMAT_X16B16G16R16I;
+		case GL_RGBA16I:        return sw::FORMAT_A16B16G16R16I;
+		case GL_R16UI:          return sw::FORMAT_R16UI;
+		case GL_RG16UI:         return sw::FORMAT_G16R16UI;
+		case GL_RGB16UI:        return sw::FORMAT_X16B16G16R16UI;
+		case GL_RGBA16UI:       return sw::FORMAT_A16B16G16R16UI;
+		case GL_R32I:           return sw::FORMAT_R32I;
+		case GL_RG32I:          return sw::FORMAT_G32R32I;
+		case GL_RGB32I:         return sw::FORMAT_X32B32G32R32I;
+		case GL_RGBA32I:        return sw::FORMAT_A32B32G32R32I;
+		case GL_R32UI:          return sw::FORMAT_R32UI;
+		case GL_RG32UI:         return sw::FORMAT_G32R32UI;
+		case GL_RGB32UI:        return sw::FORMAT_X32B32G32R32UI;
+		case GL_RGBA32UI:       return sw::FORMAT_A32B32G32R32UI;
+		case GL_R16F:           return sw::FORMAT_R16F;
+		case GL_RG16F:          return sw::FORMAT_G16R16F;
+		case GL_R11F_G11F_B10F: return sw::FORMAT_X16B16G16R16F_UNSIGNED;
+		case GL_RGB16F:         return sw::FORMAT_X16B16G16R16F;
+		case GL_RGBA16F:        return sw::FORMAT_A16B16G16R16F;
+		case GL_R32F:           return sw::FORMAT_R32F;
+		case GL_RG32F:          return sw::FORMAT_G32R32F;
+		case GL_RGB32F:         return sw::FORMAT_X32B32G32R32F;
+		case GL_RGBA32F:        return sw::FORMAT_A32B32G32R32F;
+		case GL_RGB10_A2:       return sw::FORMAT_A2B10G10R10;
+		case GL_RGB10_A2UI:     return sw::FORMAT_A2B10G10R10UI;
+		case GL_SRGB8:          return sw::FORMAT_SRGB8_X8;
+		case GL_SRGB8_ALPHA8:   return sw::FORMAT_SRGB8_A8;
+
+		case GL_ETC1_RGB8_OES:              return sw::FORMAT_ETC1;
+		case GL_COMPRESSED_R11_EAC:         return sw::FORMAT_R11_EAC;
+		case GL_COMPRESSED_SIGNED_R11_EAC:  return sw::FORMAT_SIGNED_R11_EAC;
+		case GL_COMPRESSED_RG11_EAC:        return sw::FORMAT_RG11_EAC;
+		case GL_COMPRESSED_SIGNED_RG11_EAC: return sw::FORMAT_SIGNED_RG11_EAC;
+		case GL_COMPRESSED_RGB8_ETC2:       return sw::FORMAT_RGB8_ETC2;
+		case GL_COMPRESSED_SRGB8_ETC2:      return sw::FORMAT_SRGB8_ETC2;
+		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:  return sw::FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return sw::FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+		case GL_COMPRESSED_RGBA8_ETC2_EAC:        return sw::FORMAT_RGBA8_ETC2_EAC;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return sw::FORMAT_SRGB8_ALPHA8_ETC2_EAC;
+		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:   return sw::FORMAT_RGBA_ASTC_4x4_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:   return sw::FORMAT_RGBA_ASTC_5x4_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:   return sw::FORMAT_RGBA_ASTC_5x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:   return sw::FORMAT_RGBA_ASTC_6x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:   return sw::FORMAT_RGBA_ASTC_6x6_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:   return sw::FORMAT_RGBA_ASTC_8x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:   return sw::FORMAT_RGBA_ASTC_8x6_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:   return sw::FORMAT_RGBA_ASTC_8x8_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:  return sw::FORMAT_RGBA_ASTC_10x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:  return sw::FORMAT_RGBA_ASTC_10x6_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:  return sw::FORMAT_RGBA_ASTC_10x8_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return sw::FORMAT_RGBA_ASTC_10x10_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return sw::FORMAT_RGBA_ASTC_12x10_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return sw::FORMAT_RGBA_ASTC_12x12_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:  return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:  return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:  return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR;
+		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:    return sw::FORMAT_DXT1;
+		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:   return sw::FORMAT_DXT1;
+		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return sw::FORMAT_DXT3;
+		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return sw::FORMAT_DXT5;
+
+		case GL_ALPHA32F_EXT:           return sw::FORMAT_A32F;
+		case GL_LUMINANCE32F_EXT:       return sw::FORMAT_L32F;
+		case GL_LUMINANCE_ALPHA32F_EXT: return sw::FORMAT_A32L32F;
+		case GL_RGB9_E5:                return sw::FORMAT_X16B16G16R16F_UNSIGNED;
+		case GL_ALPHA16F_EXT:           return sw::FORMAT_A16F;
+		case GL_LUMINANCE16F_EXT:       return sw::FORMAT_L16F;
+		case GL_LUMINANCE_ALPHA16F_EXT: return sw::FORMAT_A16L16F;
+		case GL_R8_SNORM:    return sw::FORMAT_R8_SNORM;
+		case GL_RG8_SNORM:   return sw::FORMAT_G8R8_SNORM;
+		case GL_RGB8_SNORM:  return sw::FORMAT_X8B8G8R8_SNORM;
+		case GL_RGBA8_SNORM: return sw::FORMAT_A8B8G8R8_SNORM;
+		case GL_LUMINANCE8_EXT:        return sw::FORMAT_L8;
+		case GL_LUMINANCE8_ALPHA8_EXT: return sw::FORMAT_A8L8;
+		case GL_BGRA8_EXT:  return sw::FORMAT_A8R8G8B8;
+		case GL_ALPHA8_EXT: return sw::FORMAT_A8;
+
+		case SW_YV12_BT601: return sw::FORMAT_YV12_BT601;
+		case SW_YV12_BT709: return sw::FORMAT_YV12_BT709;
+		case SW_YV12_JFIF:  return sw::FORMAT_YV12_JFIF;
+
+		default:
+			UNREACHABLE(format);   // Not a sized internal format.
+			return sw::FORMAT_NULL;
+		}
 	}
 
 	// Returns the size, in bytes, of a single client-side pixel.
@@ -1013,7 +675,7 @@
 		return (rawPitch + alignment - 1) & ~(alignment - 1);
 	}
 
-	size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const PixelStorageModes &storageModes)
+	size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const gl::PixelStorageModes &storageModes)
 	{
 		GLsizei pitchB = ComputePitch(width, format, type, storageModes.alignment);
 		return (storageModes.skipImages * height + storageModes.skipRows) * pitchB + storageModes.skipPixels * ComputePixelSize(format, type);
@@ -1024,6 +686,11 @@
 		return ComputeCompressedSize(width, 1, format);
 	}
 
+	inline int GetNumCompressedBlocks(int w, int h, int blockSizeX, int blockSizeY)
+	{
+		return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY);
+	}
+
 	GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format)
 	{
 		switch(format)
@@ -1037,7 +704,7 @@
 		case GL_COMPRESSED_SRGB8_ETC2:
 		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-			return 8 * getNumBlocks(width, height, 4, 4);
+			return 8 * GetNumCompressedBlocks(width, height, 4, 4);
 		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
 		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
 		case GL_COMPRESSED_RG11_EAC:
@@ -1046,62 +713,450 @@
 		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
 		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-			return 16 * getNumBlocks(width, height, 4, 4);
+			return 16 * GetNumCompressedBlocks(width, height, 4, 4);
 		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-			return 16 * getNumBlocks(width, height, 5, 4);
+			return 16 * GetNumCompressedBlocks(width, height, 5, 4);
 		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-			return 16 * getNumBlocks(width, height, 5, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 5, 5);
 		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-			return 16 * getNumBlocks(width, height, 6, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 6, 5);
 		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-			return 16 * getNumBlocks(width, height, 6, 6);
+			return 16 * GetNumCompressedBlocks(width, height, 6, 6);
 		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-			return 16 * getNumBlocks(width, height, 8, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 8, 5);
 		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-			return 16 * getNumBlocks(width, height, 8, 6);
+			return 16 * GetNumCompressedBlocks(width, height, 8, 6);
 		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-			return 16 * getNumBlocks(width, height, 8, 8);
+			return 16 * GetNumCompressedBlocks(width, height, 8, 8);
 		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-			return 16 * getNumBlocks(width, height, 10, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 5);
 		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-			return 16 * getNumBlocks(width, height, 10, 6);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 6);
 		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-			return 16 * getNumBlocks(width, height, 10, 8);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 8);
 		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-			return 16 * getNumBlocks(width, height, 10, 10);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 10);
 		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-			return 16 * getNumBlocks(width, height, 12, 10);
+			return 16 * GetNumCompressedBlocks(width, height, 12, 10);
 		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-			return 16 * getNumBlocks(width, height, 12, 12);
+			return 16 * GetNumCompressedBlocks(width, height, 12, 12);
 		default:
+			UNREACHABLE(format);
 			return 0;
 		}
 	}
+}
+
+namespace egl
+{
+	enum TransferType
+	{
+		Bytes,
+		RGB8toRGBX8,
+		RGB16toRGBX16,
+		RGB32toRGBX32,
+		RGB32FtoRGBX32F,
+		RGB16FtoRGBX16F,
+		RGBA4toRGBA8,
+		RGBA5_A1toRGBA8,
+		R11G11B10FtoRGBX16F,
+		RGB9_E5FtoRGBX16F,
+		D16toD32F,
+		D24X8toD32F,
+		D32toD32F,
+		D32FtoD32F_CLAMPED,
+		D32FX32toD32F,
+		X24S8toS8,
+		X56S8toS8,
+		RGBA1010102toRGBA8,
+		RGB8toRGB565,
+		R32FtoR16F,
+		RG32FtoRG16F,
+		RGB32FtoRGB16F,
+		RGB32FtoRGB16F_UNSIGNED,
+		RGBA32FtoRGBA16F
+	};
+
+	template<TransferType transferType>
+	void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes);
+
+	template<>
+	void TransferRow<Bytes>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		memcpy(dest, source, width * bytes);
+	}
+
+	template<>
+	void TransferRow<RGB8toRGBX8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		unsigned char *destB = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			destB[4 * x + 0] = source[x * 3 + 0];
+			destB[4 * x + 1] = source[x * 3 + 1];
+			destB[4 * x + 2] = source[x * 3 + 2];
+			destB[4 * x + 3] = 0xFF;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB16toRGBX16>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *sourceS = reinterpret_cast<const unsigned short*>(source);
+		unsigned short *destS = reinterpret_cast<unsigned short*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destS[4 * x + 0] = sourceS[x * 3 + 0];
+			destS[4 * x + 1] = sourceS[x * 3 + 1];
+			destS[4 * x + 2] = sourceS[x * 3 + 2];
+			destS[4 * x + 3] = 0xFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32toRGBX32>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
+		unsigned int *destI = reinterpret_cast<unsigned int*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destI[4 * x + 0] = sourceI[x * 3 + 0];
+			destI[4 * x + 1] = sourceI[x * 3 + 1];
+			destI[4 * x + 2] = sourceI[x * 3 + 2];
+			destI[4 * x + 3] = 0xFFFFFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32FtoRGBX32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *sourceF = reinterpret_cast<const float*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[4 * x + 0] = sourceF[x * 3 + 0];
+			destF[4 * x + 1] = sourceF[x * 3 + 1];
+			destF[4 * x + 2] = sourceF[x * 3 + 2];
+			destF[4 * x + 3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB16FtoRGBX16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
+		unsigned short *destH = reinterpret_cast<unsigned short*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destH[4 * x + 0] = sourceH[x * 3 + 0];
+			destH[4 * x + 1] = sourceH[x * 3 + 1];
+			destH[4 * x + 2] = sourceH[x * 3 + 2];
+			destH[4 * x + 3] = 0x3C00;   // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16-bit floating-point representation of 1.0
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA4toRGBA8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *source4444 = reinterpret_cast<const unsigned short*>(source);
+		unsigned char *dest4444 = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			unsigned short rgba = source4444[x];
+			dest4444[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+			dest4444[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+			dest4444[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+			dest4444[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA5_A1toRGBA8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *source5551 = reinterpret_cast<const unsigned short*>(source);
+		unsigned char *dest8888 = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			unsigned short rgba = source5551[x];
+			dest8888[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+			dest8888[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+			dest8888[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+			dest8888[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA1010102toRGBA8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *source1010102 = reinterpret_cast<const unsigned int*>(source);
+		unsigned char *dest8888 = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			unsigned int rgba = source1010102[x];
+			dest8888[4 * x + 0] = sw::unorm<8>((rgba & 0x000003FF) * (1.0f / 0x000003FF));
+			dest8888[4 * x + 1] = sw::unorm<8>((rgba & 0x000FFC00) * (1.0f / 0x000FFC00));
+			dest8888[4 * x + 2] = sw::unorm<8>((rgba & 0x3FF00000) * (1.0f / 0x3FF00000));
+			dest8888[4 * x + 3] = sw::unorm<8>((rgba & 0xC0000000) * (1.0f / 0xC0000000));
+		}
+	}
+
+	template<>
+	void TransferRow<RGB8toRGB565>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		unsigned short *dest565 = reinterpret_cast<unsigned short*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			float r = source[3 * x + 0] * (1.0f / 0xFF);
+			float g = source[3 * x + 1] * (1.0f / 0xFF);
+			float b = source[3 * x + 2] * (1.0f / 0xFF);
+			dest565[x] = (sw::unorm<5>(r) << 11) | (sw::unorm<6>(g) << 5) | (sw::unorm<5>(b) << 0);
+		}
+	}
+
+	template<>
+	void TransferRow<R11G11B10FtoRGBX16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const sw::R11G11B10F *sourceRGB = reinterpret_cast<const sw::R11G11B10F*>(source);
+		sw::half *destF = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++, sourceRGB++, destF += 4)
+		{
+			sourceRGB->toRGB16F(destF);
+			destF[3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB9_E5FtoRGBX16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const sw::RGB9E5 *sourceRGB = reinterpret_cast<const sw::RGB9E5*>(source);
+		sw::half *destF = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++, sourceRGB++, destF += 4)
+		{
+			sourceRGB->toRGB16F(destF);
+			destF[3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<R32FtoR16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[x] = source32F[x];
+		}
+	}
+
+	template<>
+	void TransferRow<RG32FtoRG16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[2 * x + 0] = source32F[2 * x + 0];
+			dest16F[2 * x + 1] = source32F[2 * x + 1];
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32FtoRGB16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[4 * x + 0] = source32F[3 * x + 0];
+			dest16F[4 * x + 1] = source32F[3 * x + 1];
+			dest16F[4 * x + 2] = source32F[3 * x + 2];
+			dest16F[4 * x + 3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32FtoRGB16F_UNSIGNED>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[4 * x + 0] = std::max(source32F[3 * x + 0], 0.0f);
+			dest16F[4 * x + 1] = std::max(source32F[3 * x + 1], 0.0f);
+			dest16F[4 * x + 2] = std::max(source32F[3 * x + 2], 0.0f);
+			dest16F[4 * x + 3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA32FtoRGBA16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[4 * x + 0] = source32F[4 * x + 0];
+			dest16F[4 * x + 1] = source32F[4 * x + 1];
+			dest16F[4 * x + 2] = source32F[4 * x + 2];
+			dest16F[4 * x + 3] = source32F[4 * x + 3];
+		}
+	}
+
+	template<>
+	void TransferRow<D16toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = (float)sourceD16[x] / 0xFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<D24X8toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceD24 = reinterpret_cast<const unsigned int*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = (float)(sourceD24[x] & 0xFFFFFF00) / 0xFFFFFF00;
+		}
+	}
+
+	template<>
+	void TransferRow<D32toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceD32 = reinterpret_cast<const unsigned int*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = (float)sourceD32[x] / 0xFFFFFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<D32FtoD32F_CLAMPED>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *sourceF = reinterpret_cast<const float*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = sw::clamp(sourceF[x], 0.0f, 1.0f);
+		}
+	}
+
+	template<>
+	void TransferRow<D32FX32toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
+		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = sw::clamp(sourceD32FS8[x].depth32f, 0.0f, 1.0f);
+		}
+	}
+
+	template<>
+	void TransferRow<X24S8toS8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
+		unsigned char *destI = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			destI[x] = static_cast<unsigned char>(sourceI[x] & 0x000000FF);   // FIXME: Quad layout
+		}
+	}
+
+	template<>
+	void TransferRow<X56S8toS8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
+		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
+		unsigned char *destI = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			destI[x] = static_cast<unsigned char>(sourceD32FS8[x].stencil24_8 & 0x000000FF);   // FIXME: Quad layout
+		}
+	}
+
+	struct Rectangle
+	{
+		GLsizei bytes;
+		GLsizei width;
+		GLsizei height;
+		GLsizei depth;
+		int inputPitch;
+		int inputHeight;
+		int destPitch;
+		GLsizei destSlice;
+	};
+
+	template<TransferType transferType>
+	void Transfer(void *buffer, const void *input, const Rectangle &rect)
+	{
+		for(int z = 0; z < rect.depth; z++)
+		{
+			const unsigned char *inputStart = static_cast<const unsigned char*>(input) + (z * rect.inputPitch * rect.inputHeight);
+			unsigned char *destStart = static_cast<unsigned char*>(buffer) + (z * rect.destSlice);
+			for(int y = 0; y < rect.height; y++)
+			{
+				const unsigned char *source = inputStart + y * rect.inputPitch;
+				unsigned char *dest = destStart + y * rect.destPitch;
+
+				TransferRow<transferType>(dest, source, rect.width, rect.bytes);
+			}
+		}
+	}
 
 	class ImageImplementation : public Image
 	{
 	public:
-		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
-			: Image(parentTexture, width, height, format, type) {}
-		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLenum format, GLenum type)
-			: Image(parentTexture, width, height, depth, border, format, type) {}
-		ImageImplementation(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP)
-			: Image(width, height, format, type, pitchP) {}
-		ImageImplementation(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable)
-			: Image(width, height, internalFormat, multiSampleDepth, lockable) {}
+		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
+			: Image(parentTexture, width, height, internalformat) {}
+		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
+			: Image(parentTexture, width, height, depth, border, internalformat) {}
+		ImageImplementation(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
+			: Image(width, height, internalformat, pitchP) {}
+		ImageImplementation(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
+			: Image(width, height, internalformat, multiSampleDepth, lockable) {}
 
 		~ImageImplementation() override
 		{
@@ -1124,24 +1179,24 @@
 		}
 	};
 
-	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
+	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
 	{
-		return new ImageImplementation(parentTexture, width, height, format, type);
+		return new ImageImplementation(parentTexture, width, height, internalformat);
 	}
 
-	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLenum format, GLenum type)
+	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
 	{
-		return new ImageImplementation(parentTexture, width, height, depth, border, format, type);
+		return new ImageImplementation(parentTexture, width, height, depth, border, internalformat);
 	}
 
-	Image *Image::create(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP)
+	Image *Image::create(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
 	{
-		return new ImageImplementation(width, height, format, type, pitchP);
+		return new ImageImplementation(width, height, internalformat, pitchP);
 	}
 
-	Image *Image::create(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable)
+	Image *Image::create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
 	{
-		return new ImageImplementation(width, height, internalFormat, multiSampleDepth, lockable);
+		return new ImageImplementation(width, height, internalformat, multiSampleDepth, lockable);
 	}
 
 	Image::~Image()
@@ -1200,260 +1255,377 @@
 		return parentTexture == parent;
 	}
 
-	void Image::loadImageData(Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelStorageModes &unpackParameters, const void *pixels)
+	void Image::loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer)
 	{
-		sw::Format uploadFormat = SelectInternalFormat(format, type);
-		if(uploadFormat == sw::FORMAT_NULL)
+		Rectangle rect;
+		rect.bytes = gl::ComputePixelSize(format, type);
+		rect.width = width;
+		rect.height = height;
+		rect.depth = depth;
+		rect.inputPitch = inputPitch;
+		rect.inputHeight = inputHeight;
+		rect.destPitch = getPitch();
+		rect.destSlice = getSlice();
+
+		// [OpenGL ES 3.0.5] table 3.2 and 3.3.
+		switch(format)
 		{
-			return;
-		}
-
-		GLsizei inputWidth = (unpackParameters.rowLength == 0) ? width : unpackParameters.rowLength;
-		GLsizei inputPitch = ComputePitch(inputWidth, format, type, unpackParameters.alignment);
-		GLsizei inputHeight = (unpackParameters.imageHeight == 0) ? height : unpackParameters.imageHeight;
-		char *input = ((char*)pixels) + ComputePackingOffset(format, type, inputWidth, inputHeight, unpackParameters);
-
-		if(uploadFormat == internalFormat ||
-		   (uploadFormat == sw::FORMAT_A8B8G8R8 && internalFormat == sw::FORMAT_SRGB8_A8) ||
-		   (uploadFormat == sw::FORMAT_X8B8G8R8 && internalFormat == sw::FORMAT_SRGB8_X8) ||
-		   (uploadFormat == sw::FORMAT_A2B10G10R10 && internalFormat == sw::FORMAT_A2B10G10R10UI))
-		{
-			void *buffer = lock(xoffset, yoffset, zoffset, sw::LOCK_WRITEONLY);
-
-			if(buffer)
+		case GL_RGBA:
+			switch(type)
 			{
-				// OpenGL ES 3.0.5 table 3.2.
-				switch(format)
+			case GL_UNSIGNED_BYTE:
+				switch(internalformat)
 				{
-				case GL_RED:
-				case GL_RED_INTEGER:
-				case GL_ALPHA:
-				case GL_LUMINANCE:
-					switch(type)
-					{
-					case GL_BYTE:
-					case GL_UNSIGNED_BYTE:
-						LoadImageData<Bytes_1>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_FLOAT:
-						ASSERT(format != GL_RED_INTEGER);
-						LoadImageData<Bytes_4>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_HALF_FLOAT:
-					case GL_HALF_FLOAT_OES:
-						ASSERT(format != GL_RED_INTEGER);
-						LoadImageData<Bytes_2>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_SHORT:
-					case GL_UNSIGNED_SHORT:
-						LoadImageData<Bytes_2>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_INT:
-					case GL_UNSIGNED_INT:
-						LoadImageData<Bytes_4>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					default:
-						UNREACHABLE(type);
-					}
-					break;
-				case GL_RG:
-				case GL_RG_INTEGER:
-				case GL_LUMINANCE_ALPHA:
-					switch(type)
-					{
-					case GL_BYTE:
-					case GL_UNSIGNED_BYTE:
-						LoadImageData<Bytes_2>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_FLOAT:
-						ASSERT(format != GL_RG_INTEGER);
-						LoadImageData<Bytes_8>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_HALF_FLOAT:
-					case GL_HALF_FLOAT_OES:
-						ASSERT(format != GL_RG_INTEGER);
-						LoadImageData<Bytes_4>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_SHORT:
-					case GL_UNSIGNED_SHORT:
-						LoadImageData<Bytes_4>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_INT:
-					case GL_UNSIGNED_INT:
-						LoadImageData<Bytes_8>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					default:
-						UNREACHABLE(type);
-					}
-					break;
-				case GL_RGB:
-				case GL_RGB_INTEGER:
-					switch(type)
-					{
-					case GL_BYTE:
-						LoadImageData<ByteRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_BYTE:
-						LoadImageData<UByteRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_SHORT_5_6_5:
-						ASSERT(format == GL_RGB);
-						LoadImageData<Bytes_2>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_INT_10F_11F_11F_REV:
-						ASSERT(format == GL_RGB);
-						LoadImageData<R11G11B10F>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_INT_5_9_9_9_REV:
-						ASSERT(format == GL_RGB);
-						LoadImageData<RGB9E5>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_FLOAT:
-						ASSERT(format == GL_RGB);
-						LoadImageData<FloatRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_HALF_FLOAT:
-					case GL_HALF_FLOAT_OES:
-						ASSERT(format == GL_RGB);
-						LoadImageData<HalfFloatRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_SHORT:
-						LoadImageData<ShortRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_SHORT:
-						LoadImageData<UShortRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_INT:
-						LoadImageData<IntRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_INT:
-						LoadImageData<UIntRGB>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					default:
-						UNREACHABLE(type);
-					}
-					break;
-				case GL_RGBA:
-				case GL_RGBA_INTEGER:
-				case GL_BGRA_EXT:
-					switch(type)
-					{
-					case GL_BYTE:
-					case GL_UNSIGNED_BYTE:
-						LoadImageData<Bytes_4>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_SHORT_4_4_4_4:
-						ASSERT(format == GL_RGBA);
-						LoadImageData<RGBA4444>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-				//	case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
-				//		ASSERT(format == GL_BGRA_EXT);
-				//		LoadImageData<ABGR4444>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-				//		break;
-					case GL_UNSIGNED_SHORT_5_5_5_1:
-						ASSERT(format == GL_RGBA);
-						LoadImageData<RGBA5551>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-				//	case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
-				//		ASSERT(format == GL_BGRA_EXT);
-				//		LoadImageData<ABGR5551>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-				//		break;
-					case GL_UNSIGNED_INT_2_10_10_10_REV:
-						ASSERT(format != GL_BGRA_EXT);
-						LoadImageData<Bytes_4>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_FLOAT:
-						ASSERT(format == GL_RGBA);
-						LoadImageData<Bytes_16>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_HALF_FLOAT:
-					case GL_HALF_FLOAT_OES:
-						ASSERT(format == GL_RGBA);
-						LoadImageData<Bytes_8>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_SHORT:
-					case GL_UNSIGNED_SHORT:
-						ASSERT(format != GL_BGRA_EXT);
-						LoadImageData<Bytes_8>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_INT:
-					case GL_UNSIGNED_INT:
-						ASSERT(format != GL_BGRA_EXT);
-						LoadImageData<Bytes_16>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					default:
-						UNREACHABLE(type);
-					}
-					break;
-				case GL_DEPTH_COMPONENT:
-					switch(type)
-					{
-					case GL_FLOAT:
-						LoadImageData<D32F>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_SHORT:
-						LoadImageData<D16>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					case GL_UNSIGNED_INT:
-						LoadImageData<D32>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
-						break;
-					default:
-						UNREACHABLE(type);
-					}
-					break;
-				case GL_DEPTH_STENCIL:
-					switch(type)
-					{
-					case GL_UNSIGNED_INT_24_8:
-						loadD24S8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer);
-						break;
-					case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-						loadD32FS8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer);
-						break;
-					default:
-						UNREACHABLE(type);
-					}
-					break;
+				case GL_RGBA8:
+				case GL_SRGB8_ALPHA8:
+					return Transfer<Bytes>(buffer, input, rect);
+				case GL_RGB5_A1:
+				case GL_RGBA4:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A8B8G8R8);
+					return Transfer<Bytes>(buffer, input, rect);
 				default:
-					UNREACHABLE(format);
+					UNREACHABLE(internalformat);
 				}
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA8_SNORM && getExternalFormat() == sw::FORMAT_A8B8G8R8_SNORM);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_4_4_4_4:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA4 && getExternalFormat() == sw::FORMAT_A8B8G8R8);
+				return Transfer<RGBA4toRGBA8>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_5_5_5_1:
+				ASSERT_OR_RETURN(internalformat == GL_RGB5_A1 && getExternalFormat() == sw::FORMAT_A8B8G8R8);
+				return Transfer<RGBA5_A1toRGBA8>(buffer, input, rect);
+			case GL_UNSIGNED_INT_2_10_10_10_REV:
+				switch(internalformat)
+				{
+				case GL_RGB10_A2:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A2B10G10R10);
+					return Transfer<Bytes>(buffer, input, rect);
+				case GL_RGB5_A1:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A8B8G8R8);
+					return Transfer<RGBA1010102toRGBA8>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
+				}
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA16F && getExternalFormat() == sw::FORMAT_A16B16G16R16F);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RGBA32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_RGBA16F: return Transfer<RGBA32FtoRGBA16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
 			}
-
-			unlock();
-		}
-		else
-		{
-			sw::Surface *source = sw::Surface::create(width, height, depth, ConvertFormatType(format, type), input, inputPitch, inputPitch * inputHeight);
-			sw::Rect sourceRect(0, 0, width, height);
-			sw::Rect destRect(xoffset, yoffset, xoffset + width, yoffset + height);
-			context->blit(source, sourceRect, this, destRect);
-			delete source;
+		case GL_RGBA_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA8UI && getExternalFormat() == sw::FORMAT_A8B8G8R8UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA8I && getExternalFormat() == sw::FORMAT_A8B8G8R8I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA16UI && getExternalFormat() == sw::FORMAT_A16B16G16R16UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA16I && getExternalFormat() == sw::FORMAT_A16B16G16R16I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA32UI && getExternalFormat() == sw::FORMAT_A32B32G32R32UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA32I && getExternalFormat() == sw::FORMAT_A32B32G32R32I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT_2_10_10_10_REV:
+				ASSERT_OR_RETURN(internalformat == GL_RGB10_A2UI && getExternalFormat() == sw::FORMAT_A2B10G10R10UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_BGRA_EXT:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_BGRA8_EXT && getExternalFormat() == sw::FORMAT_A8R8G8B8);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:   // Only valid for glReadPixels calls.
+			case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:   // Only valid for glReadPixels calls.
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RGB:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				switch(internalformat)
+				{
+				case GL_RGB8:   return Transfer<RGB8toRGBX8>(buffer, input, rect);
+				case GL_SRGB8:  return Transfer<RGB8toRGBX8>(buffer, input, rect);
+				case GL_RGB565: return Transfer<RGB8toRGB565>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGB8_SNORM && getExternalFormat() == sw::FORMAT_X8B8G8R8_SNORM);
+				return Transfer<RGB8toRGBX8>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_5_6_5:
+				ASSERT_OR_RETURN(internalformat == GL_RGB565 && getExternalFormat() == sw::FORMAT_R5G6B5);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT_10F_11F_11F_REV:
+				ASSERT_OR_RETURN(internalformat == GL_R11F_G11F_B10F && getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+				return Transfer<R11G11B10FtoRGBX16F>(buffer, input, rect);
+			case GL_UNSIGNED_INT_5_9_9_9_REV:
+				ASSERT_OR_RETURN(internalformat == GL_RGB9_E5 && getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+				return Transfer<RGB9_E5FtoRGBX16F>(buffer, input, rect);
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				switch(internalformat)
+				{
+				case GL_RGB16F:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F);
+					return Transfer<RGB16FtoRGBX16F>(buffer, input, rect);
+				case GL_R11F_G11F_B10F:
+				case GL_RGB9_E5:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+					return Transfer<RGB16FtoRGBX16F>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
+				}
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RGB32F:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X32B32G32R32F);
+					return Transfer<RGB32FtoRGBX32F>(buffer, input, rect);
+				case GL_RGB16F:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F);
+					return Transfer<RGB32FtoRGB16F>(buffer, input, rect);
+				case GL_R11F_G11F_B10F:
+				case GL_RGB9_E5:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+					return Transfer<RGB32FtoRGB16F_UNSIGNED>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RGB_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGB8UI && getExternalFormat() == sw::FORMAT_X8B8G8R8UI);
+				return Transfer<RGB8toRGBX8>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGB8I && getExternalFormat() == sw::FORMAT_X8B8G8R8I);
+				return Transfer<RGB8toRGBX8>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB16UI && getExternalFormat() == sw::FORMAT_X16B16G16R16UI);
+				return Transfer<RGB16toRGBX16>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB16I && getExternalFormat() == sw::FORMAT_X16B16G16R16I);
+				return Transfer<RGB16toRGBX16>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB32UI && getExternalFormat() == sw::FORMAT_X32B32G32R32UI);
+				return Transfer<RGB32toRGBX32>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB32I && getExternalFormat() == sw::FORMAT_X32B32G32R32I);
+				return Transfer<RGB32toRGBX32>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RG:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+			case GL_BYTE:
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RG32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_RG16F: return Transfer<RG32FtoRG16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RG_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RG8UI && getExternalFormat() == sw::FORMAT_G8R8UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RG8I && getExternalFormat() == sw::FORMAT_G8R8I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RG16UI && getExternalFormat() == sw::FORMAT_G16R16UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RG16I && getExternalFormat() == sw::FORMAT_G16R16I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RG32UI && getExternalFormat() == sw::FORMAT_G32R32UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RG32I && getExternalFormat() == sw::FORMAT_G32R32I);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RED:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+			case GL_BYTE:
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_R32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_R16F: return Transfer<R32FtoR16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RED_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_R8UI && getExternalFormat() == sw::FORMAT_R8UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_R8I && getExternalFormat() == sw::FORMAT_R8I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_R16UI && getExternalFormat() == sw::FORMAT_R16UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_R16I && getExternalFormat() == sw::FORMAT_R16I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_R32UI && getExternalFormat() == sw::FORMAT_R32UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_R32I && getExternalFormat() == sw::FORMAT_R32I);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_DEPTH_COMPONENT:
+			switch(type)
+			{
+			case GL_UNSIGNED_SHORT: return Transfer<D16toD32F>(buffer, input, rect);
+			case GL_UNSIGNED_INT:   return Transfer<D32toD32F>(buffer, input, rect);
+			case GL_FLOAT:          return Transfer<D32FtoD32F_CLAMPED>(buffer, input, rect);
+			case GL_DEPTH_COMPONENT24:       // Only valid for glRenderbufferStorage calls.
+			case GL_DEPTH_COMPONENT32_OES:   // Only valid for glRenderbufferStorage calls.
+			default: UNREACHABLE(type);
+			}
+		case GL_DEPTH_STENCIL:
+			switch(type)
+			{
+			case GL_UNSIGNED_INT_24_8:              return Transfer<D24X8toD32F>(buffer, input, rect);
+			case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return Transfer<D32FX32toD32F>(buffer, input, rect);
+			default: UNREACHABLE(type);
+			}
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RG32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_RG16F: return Transfer<RG32FtoRG16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_LUMINANCE:
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_R32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_R16F: return Transfer<R32FtoR16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		default:
+			UNREACHABLE(format);
 		}
 	}
 
-	void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer)
+	void Image::loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer)
 	{
-		LoadImageData<D24>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
+		Rectangle rect;
+		rect.bytes = gl::ComputePixelSize(format, type);
+		rect.width = width;
+		rect.height = height;
+		rect.depth = depth;
+		rect.inputPitch = inputPitch;
+		rect.inputHeight = inputHeight;
+		rect.destPitch = getStencilPitchB();
+		rect.destSlice = getStencilSliceB();
 
-		unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, 0, 0, sw::PUBLIC));
-
-		if(stencil)
+		switch(type)
 		{
-			LoadImageData<S8>(width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil);
-
-			unlockStencil();
+		case GL_UNSIGNED_INT_24_8:              return Transfer<X24S8toS8>(buffer, input, rect);
+		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return Transfer<X56S8toS8>(buffer, input, rect);
+		default: UNREACHABLE(format);
 		}
 	}
 
-	void Image::loadD32FS8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer)
+	void Image::loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 	{
-		LoadImageData<D32FS8>(width, height, depth, inputPitch, inputHeight, getPitch(), getSlice(), input, buffer);
+		GLsizei inputWidth = (unpackParameters.rowLength == 0) ? width : unpackParameters.rowLength;
+		GLsizei inputPitch = gl::ComputePitch(inputWidth, format, type, unpackParameters.alignment);
+		GLsizei inputHeight = (unpackParameters.imageHeight == 0) ? height : unpackParameters.imageHeight;
+		char *input = ((char*)pixels) + gl::ComputePackingOffset(format, type, inputWidth, inputHeight, unpackParameters);
 
-		unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, 0, 0, sw::PUBLIC));
+		void *buffer = lock(xoffset, yoffset, zoffset, sw::LOCK_WRITEONLY);
 
-		if(stencil)
+		if(buffer)
 		{
-			LoadImageData<S24_8>(width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil);
+			loadImageData(width, height, depth, inputPitch, inputHeight, format, type, input, buffer);
+		}
+
+		unlock();
+
+		if(hasStencil())
+		{
+			unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(xoffset, yoffset, zoffset, sw::PUBLIC));
+
+			if(stencil)
+			{
+				loadStencilData(width, height, depth, inputPitch, inputHeight, format, type, input, stencil);
+			}
 
 			unlockStencil();
 		}
@@ -1461,7 +1633,7 @@
 
 	void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
 	{
-		int inputPitch = ComputeCompressedPitch(width, format);
+		int inputPitch = gl::ComputeCompressedPitch(width, internalformat);
 		int inputSlice = imageSize / depth;
 		int rows = inputSlice / inputPitch;
 
diff --git a/src/OpenGL/common/Image.hpp b/src/OpenGL/common/Image.hpp
index ff09da8..c6cc6a0 100644
--- a/src/OpenGL/common/Image.hpp
+++ b/src/OpenGL/common/Image.hpp
@@ -36,11 +36,9 @@
 #define SW_YV12_BT709 0x48315659   // YCrCb 4:2:0 Planar, 16-byte aligned, BT.709 color space, studio swing
 #define SW_YV12_JFIF  0x4A315659   // YCrCb 4:2:0 Planar, 16-byte aligned, BT.601 color space, full swing
 
-namespace egl
+namespace gl
 {
 
-class Context;
-
 struct PixelStorageModes
 {
 	GLint rowLength = 0;
@@ -51,20 +49,27 @@
 	GLint skipImages = 0;
 };
 
-sw::Format ConvertFormatType(GLenum format, GLenum type);
-sw::Format SelectInternalFormat(GLenum format, GLenum type);
+GLint GetSizedInternalFormat(GLint internalFormat, GLenum type);
+sw::Format ConvertReadFormatType(GLenum format, GLenum type);
+sw::Format SelectInternalFormat(GLint format);
+bool IsUnsizedInternalFormat(GLint internalformat);
+GLenum GetBaseInternalFormat(GLint internalformat);
 GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment);
 GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);
 size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const PixelStorageModes &storageModes);
 
+}
+
+namespace egl
+{
+
 class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object
 {
 protected:
 	// 2D texture image
-	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
-		: sw::Surface(parentTexture->getResource(), width, height, 1, 0, 1, SelectInternalFormat(format, type), true, true),
-		  width(width), height(height), depth(1), format(format), type(type), internalFormat(SelectInternalFormat(format, type)),
-		  parentTexture(parentTexture)
+	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
+		: sw::Surface(parentTexture->getResource(), width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true),
+		  width(width), height(height), depth(1), internalformat(internalformat), parentTexture(parentTexture)
 	{
 		shared = false;
 		Object::addRef();
@@ -72,10 +77,9 @@
 	}
 
 	// 3D/Cube texture image
-	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLenum format, GLenum type)
-		: sw::Surface(parentTexture->getResource(), width, height, depth, border, 1, SelectInternalFormat(format, type), true, true),
-		  width(width), height(height), depth(depth), format(format), type(type), internalFormat(SelectInternalFormat(format, type)),
-		  parentTexture(parentTexture)
+	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
+		: sw::Surface(parentTexture->getResource(), width, height, depth, border, 1, gl::SelectInternalFormat(internalformat), true, true),
+		  width(width), height(height), depth(depth), internalformat(internalformat), parentTexture(parentTexture)
 	{
 		shared = false;
 		Object::addRef();
@@ -83,20 +87,18 @@
 	}
 
 	// Native EGL image
-	Image(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP)
-		: sw::Surface(nullptr, width, height, 1, 0, 1, SelectInternalFormat(format, type), true, true, pitchP),
-		  width(width), height(height), depth(1), format(format), type(type), internalFormat(SelectInternalFormat(format, type)),
-		  parentTexture(nullptr)
+	Image(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
+		: sw::Surface(nullptr, width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true, pitchP),
+		  width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
 	{
 		shared = true;
 		Object::addRef();
 	}
 
 	// Render target
-	Image(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable)
-		: sw::Surface(nullptr, width, height, 1, 0, multiSampleDepth, internalFormat, lockable, true),
-		  width(width), height(height), depth(1), format(0 /*GL_NONE*/), type(0 /*GL_NONE*/), internalFormat(internalFormat),
-		  parentTexture(nullptr)
+	Image(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
+		: sw::Surface(nullptr, width, height, 1, 0, multiSampleDepth, gl::SelectInternalFormat(internalformat), lockable, true),
+		  width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
 	{
 		shared = false;
 		Object::addRef();
@@ -104,16 +106,16 @@
 
 public:
 	// 2D texture image
-	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type);
+	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat);
 
 	// 3D/Cube texture image
-	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLenum format, GLenum type);
+	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat);
 
 	// Native EGL image
-	static Image *create(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP);
+	static Image *create(GLsizei width, GLsizei height, GLint internalformat, int pitchP);
 
 	// Render target
-	static Image *create(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable);
+	static Image *create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable);
 
 	GLsizei getWidth() const
 	{
@@ -132,19 +134,9 @@
 		return depth;
 	}
 
-	GLenum getFormat() const
+	GLint getFormat() const
 	{
-		return format;
-	}
-
-	GLenum getType() const
-	{
-		return type;
-	}
-
-	sw::Format getInternalFormat() const
-	{
-		return internalFormat;
+		return internalformat;
 	}
 
 	bool isShared() const
@@ -180,7 +172,7 @@
 	void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override = 0;
 	void unlockInternal() override = 0;
 
-	void loadImageData(Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelStorageModes &unpackParameters, const void *pixels);
+	void loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
 
 	void release() override = 0;
@@ -198,9 +190,7 @@
 	const GLsizei width;
 	const GLsizei height;
 	const int depth;
-	const GLenum format;
-	const GLenum type;
-	const sw::Format internalFormat;
+	const GLint internalformat;
 
 	bool shared;   // Used as an EGLImage
 
@@ -208,8 +198,8 @@
 
 	~Image() override = 0;
 
-	void loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer);
-	void loadD32FS8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer);
+	void loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
+	void loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
 };
 
 #ifdef __ANDROID__
@@ -236,35 +226,12 @@
 	}
 }
 
-inline GLenum GLPixelTypeFromAndroid(int halFormat)
-{
-	switch(halFormat)
-	{
-	case HAL_PIXEL_FORMAT_RGBA_8888: return GL_UNSIGNED_BYTE;
-#if ANDROID_PLATFORM_SDK_VERSION > 16
-	case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return GL_UNSIGNED_BYTE;
-#endif
-	case HAL_PIXEL_FORMAT_RGBX_8888: return GL_UNSIGNED_BYTE;
-	case HAL_PIXEL_FORMAT_BGRA_8888: return GL_UNSIGNED_BYTE;
-	case HAL_PIXEL_FORMAT_RGB_565:   return GL_UNSIGNED_SHORT_5_6_5;
-	case HAL_PIXEL_FORMAT_YV12:      return GL_UNSIGNED_BYTE;
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-	case HAL_PIXEL_FORMAT_YCbCr_420_888: return GL_UNSIGNED_BYTE;
-#endif
-	case HAL_PIXEL_FORMAT_RGB_888:   // Unsupported.
-	default:
-		ALOGE("Unsupported EGL image format %d", halFormat); ASSERT(false);
-		return GL_NONE;
-	}
-}
-
 class AndroidNativeImage : public egl::Image
 {
 public:
 	explicit AndroidNativeImage(ANativeWindowBuffer *nativeBuffer)
 		: egl::Image(nativeBuffer->width, nativeBuffer->height,
 		             GLPixelFormatFromAndroid(nativeBuffer->format),
-		             GLPixelTypeFromAndroid(nativeBuffer->format),
 		             nativeBuffer->stride),
 		  nativeBuffer(nativeBuffer)
 	{
diff --git a/src/OpenGL/common/Surface.hpp b/src/OpenGL/common/Surface.hpp
index 50a9d00..493d676 100644
--- a/src/OpenGL/common/Surface.hpp
+++ b/src/OpenGL/common/Surface.hpp
@@ -40,8 +40,6 @@
 	virtual egl::Image *getRenderTarget() = 0;
 	virtual egl::Image *getDepthStencil() = 0;
 
-	virtual sw::Format getInternalFormat() const = 0;
-
 	virtual EGLint getWidth() const = 0;
 	virtual EGLint getHeight() const = 0;
 
diff --git a/src/OpenGL/libEGL/Surface.cpp b/src/OpenGL/libEGL/Surface.cpp
index 57261b2..3d17cba 100644
--- a/src/OpenGL/libEGL/Surface.cpp
+++ b/src/OpenGL/libEGL/Surface.cpp
@@ -182,11 +182,6 @@
 	return config->mSurfaceType;
 }
 
-sw::Format Surface::getInternalFormat() const
-{
-	return config->mRenderTargetFormat;
-}
-
 EGLint Surface::getWidth() const
 {
 	return width;
diff --git a/src/OpenGL/libEGL/Surface.hpp b/src/OpenGL/libEGL/Surface.hpp
index e140a8e..2e9e26b 100644
--- a/src/OpenGL/libEGL/Surface.hpp
+++ b/src/OpenGL/libEGL/Surface.hpp
@@ -45,7 +45,6 @@
 
 	virtual EGLint getConfigID() const;
 	virtual EGLenum getSurfaceType() const;
-	sw::Format getInternalFormat() const override;
 
 	EGLint getWidth() const override;
 	EGLint getHeight() const override;
diff --git a/src/OpenGL/libGL/Texture.cpp b/src/OpenGL/libGL/Texture.cpp
index 3f5102a..70ff9b2 100644
--- a/src/OpenGL/libGL/Texture.cpp
+++ b/src/OpenGL/libGL/Texture.cpp
@@ -181,7 +181,7 @@
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
 {
-	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with egl::ComputeCompressedSize() at the API level
+	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
 	}
@@ -232,7 +232,7 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with egl::ComputeCompressedSize() at the API level
+	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
 	}
diff --git a/src/OpenGL/libGLES_CM/Context.cpp b/src/OpenGL/libGLES_CM/Context.cpp
index ca2984c..91f865c 100644
--- a/src/OpenGL/libGLES_CM/Context.cpp
+++ b/src/OpenGL/libGLES_CM/Context.cpp
@@ -2413,7 +2413,7 @@
 		}
 	}
 
-	GLsizei outputPitch = egl::ComputePitch(width, format, type, mState.packAlignment);
+	GLsizei outputPitch = gl::ComputePitch(width, format, type, mState.packAlignment);
 
 	// Sized query sanity check
 	if(bufSize)
diff --git a/src/OpenGL/libGLES_CM/Device.cpp b/src/OpenGL/libGLES_CM/Device.cpp
index 23c96f4..d1c3a04 100644
--- a/src/OpenGL/libGLES_CM/Device.cpp
+++ b/src/OpenGL/libGLES_CM/Device.cpp
@@ -217,69 +217,6 @@
 		stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
 	}
 
-	egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		bool lockable = true;
-
-		switch(format)
-		{
-	//	case FORMAT_D15S1:
-		case FORMAT_D24S8:
-		case FORMAT_D24X8:
-	//	case FORMAT_D24X4S4:
-		case FORMAT_D24FS8:
-		case FORMAT_D32:
-		case FORMAT_D16:
-			lockable = false;
-			break;
-	//	case FORMAT_S8_LOCKABLE:
-	//	case FORMAT_D16_LOCKABLE:
-		case FORMAT_D32F_LOCKABLE:
-	//	case FORMAT_D32_LOCKABLE:
-		case FORMAT_DF24S8:
-		case FORMAT_DF16S8:
-			lockable = true;
-			break;
-		default:
-			UNREACHABLE(format);
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
-	egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
 	void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
 	{
 		if(!bindResources() || !primitiveCount)
diff --git a/src/OpenGL/libGLES_CM/Device.hpp b/src/OpenGL/libGLES_CM/Device.hpp
index c40e30d..ffabc45 100644
--- a/src/OpenGL/libGLES_CM/Device.hpp
+++ b/src/OpenGL/libGLES_CM/Device.hpp
@@ -49,8 +49,6 @@
 		void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);
 		void clearDepth(float z);
 		void clearStencil(unsigned int stencil, unsigned int mask);
-		egl::Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);
-		egl::Image *createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable);
 		void drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount);
 		void drawPrimitive(sw::DrawType type, unsigned int primiveCount);
 		void setScissorEnable(bool enable);
diff --git a/src/OpenGL/libGLES_CM/Framebuffer.cpp b/src/OpenGL/libGLES_CM/Framebuffer.cpp
index 933aa2a..097c6a2 100644
--- a/src/OpenGL/libGLES_CM/Framebuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Framebuffer.cpp
@@ -405,16 +405,16 @@
 
 	if(colorbuffer)
 	{
-		switch(colorbuffer->getInternalFormat())
+		switch(colorbuffer->getFormat())
 		{
-		case sw::FORMAT_A8R8G8B8: return GL_BGRA_EXT;
-		case sw::FORMAT_A8B8G8R8: return GL_RGBA;
-		case sw::FORMAT_X8R8G8B8: return GL_BGRA_EXT;
-		case sw::FORMAT_X8B8G8R8: return GL_RGBA;
-		case sw::FORMAT_A1R5G5B5: return GL_BGRA_EXT;
-		case sw::FORMAT_R5G6B5:   return GL_RGB;
+		case GL_BGRA8_EXT:   return GL_BGRA_EXT;
+		case GL_RGBA4_OES:   return GL_RGBA;
+		case GL_RGB5_A1_OES: return GL_RGBA;
+		case GL_RGBA8_OES:   return GL_RGBA;
+		case GL_RGB565_OES:  return GL_RGBA;
+		case GL_RGB8_OES:    return GL_RGB;
 		default:
-			UNREACHABLE(colorbuffer->getInternalFormat());
+			UNREACHABLE(colorbuffer->getFormat());
 		}
 	}
 
@@ -427,16 +427,16 @@
 
 	if(colorbuffer)
 	{
-		switch(colorbuffer->getInternalFormat())
+		switch(colorbuffer->getFormat())
 		{
-		case sw::FORMAT_A8R8G8B8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_A8B8G8R8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_X8R8G8B8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_X8B8G8R8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_A1R5G5B5: return GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT;
-		case sw::FORMAT_R5G6B5:   return GL_UNSIGNED_SHORT_5_6_5;
+		case GL_BGRA8_EXT:   return GL_UNSIGNED_BYTE;
+		case GL_RGBA4_OES:   return GL_UNSIGNED_SHORT_4_4_4_4;
+		case GL_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1;
+		case GL_RGBA8_OES:   return GL_UNSIGNED_BYTE;
+		case GL_RGB565_OES:  return GL_UNSIGNED_SHORT_5_6_5;
+		case GL_RGB8_OES:    return GL_UNSIGNED_BYTE;
 		default:
-			UNREACHABLE(colorbuffer->getInternalFormat());
+			UNREACHABLE(colorbuffer->getFormat());
 		}
 	}
 
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.cpp b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
index 96bf733..733b9ac 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
@@ -41,32 +41,32 @@
 
 GLuint RenderbufferInterface::getRedSize() const
 {
-	return sw2es::GetRedSize(getInternalFormat());
+	return GetRedSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getGreenSize() const
 {
-	return sw2es::GetGreenSize(getInternalFormat());
+	return GetGreenSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getBlueSize() const
 {
-	return sw2es::GetBlueSize(getInternalFormat());
+	return GetBlueSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getAlphaSize() const
 {
-	return sw2es::GetAlphaSize(getInternalFormat());
+	return GetAlphaSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getDepthSize() const
 {
-	return sw2es::GetDepthSize(getInternalFormat());
+	return GetDepthSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getStencilSize() const
 {
-	return sw2es::GetStencilSize(getInternalFormat());
+	return GetStencilSize(getFormat());
 }
 
 ///// RenderbufferTexture2D Implementation ////////
@@ -127,11 +127,6 @@
 	return mTexture2D->getFormat(GL_TEXTURE_2D, 0);
 }
 
-sw::Format RenderbufferTexture2D::getInternalFormat() const
-{
-	return mTexture2D->getInternalFormat(GL_TEXTURE_2D, 0);
-}
-
 GLsizei RenderbufferTexture2D::getSamples() const
 {
 	return 0;
@@ -200,11 +195,6 @@
 	return mInstance->getFormat();
 }
 
-sw::Format Renderbuffer::getInternalFormat() const
-{
-	return mInstance->getInternalFormat();
-}
-
 GLuint Renderbuffer::getRedSize() const
 {
 	return mInstance->getRedSize();
@@ -252,8 +242,7 @@
 {
 	mWidth = 0;
 	mHeight = 0;
-	format = GL_RGBA4_OES;
-	internalFormat = sw::FORMAT_A8B8G8R8;
+	format = GL_NONE;
 	mSamples = 0;
 }
 
@@ -276,11 +265,6 @@
 	return format;
 }
 
-sw::Format RenderbufferStorage::getInternalFormat() const
-{
-	return internalFormat;
-}
-
 GLsizei RenderbufferStorage::getSamples() const
 {
 	return mSamples;
@@ -294,22 +278,24 @@
 
 		mWidth = renderTarget->getWidth();
 		mHeight = renderTarget->getHeight();
-		internalFormat = renderTarget->getInternalFormat();
-		format = sw2es::ConvertBackBufferFormat(internalFormat);
+		format = renderTarget->getFormat();
 		mSamples = renderTarget->getDepth() & ~1;
 	}
 }
 
-Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(nullptr)
+Colorbuffer::Colorbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mRenderTarget(nullptr)
 {
-	Device *device = getDevice();
-
-	sw::Format requestedFormat = es2sw::ConvertRenderbufferFormat(format);
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mRenderTarget = device->createRenderTarget(width, height, requestedFormat, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mRenderTarget = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mRenderTarget)
 		{
@@ -320,8 +306,7 @@
 
 	mWidth = width;
 	mHeight = height;
-	this->format = format;
-	internalFormat = requestedFormat;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
@@ -371,21 +356,24 @@
 
 		mWidth = depthStencil->getWidth();
 		mHeight = depthStencil->getHeight();
-		internalFormat = depthStencil->getInternalFormat();
-		format = sw2es::ConvertDepthStencilFormat(internalFormat);
+		format = depthStencil->getFormat();
 		mSamples = depthStencil->getDepth() & ~1;
 	}
 }
 
-DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples) : mDepthStencil(nullptr)
+DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mDepthStencil(nullptr)
 {
-	Device *device = getDevice();
-
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mDepthStencil = device->createDepthStencilSurface(width, height, sw::FORMAT_D24S8, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mDepthStencil = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mDepthStencil)
 		{
@@ -396,8 +384,7 @@
 
 	mWidth = width;
 	mHeight = height;
-	format = GL_DEPTH24_STENCIL8_OES;
-	internalFormat = sw::FORMAT_D24S8;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
@@ -441,22 +428,10 @@
 
 Depthbuffer::Depthbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil)
 {
-	if(depthStencil)
-	{
-		format = GL_DEPTH_COMPONENT16_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                     // will expect one of the valid renderbuffer formats for use in
-		                                     // glRenderbufferStorage
-	}
 }
 
-Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+Depthbuffer::Depthbuffer(int width, int height, GLenum internalformat, GLsizei samples) : DepthStencilbuffer(width, height, internalformat, samples)
 {
-	if(mDepthStencil)
-	{
-		format = GL_DEPTH_COMPONENT16_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                     // will expect one of the valid renderbuffer formats for use in
-		                                     // glRenderbufferStorage
-	}
 }
 
 Depthbuffer::~Depthbuffer()
@@ -465,22 +440,10 @@
 
 Stencilbuffer::Stencilbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil)
 {
-	if(depthStencil)
-	{
-		format = GL_STENCIL_INDEX8_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                  // will expect one of the valid renderbuffer formats for use in
-		                                  // glRenderbufferStorage
-	}
 }
 
-Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, GL_STENCIL_INDEX8_OES, samples)
 {
-	if(mDepthStencil)
-	{
-		format = GL_STENCIL_INDEX8_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                  // will expect one of the valid renderbuffer formats for use in
-		                                  // glRenderbufferStorage
-	}
 }
 
 Stencilbuffer::~Stencilbuffer()
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.h b/src/OpenGL/libGLES_CM/Renderbuffer.h
index 6bb462f..f5275f9 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.h
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.h
@@ -49,7 +49,6 @@
 	virtual GLsizei getWidth() const = 0;
 	virtual GLsizei getHeight() const = 0;
 	virtual GLenum getFormat() const = 0;
-	virtual sw::Format getInternalFormat() const = 0;
 	virtual GLsizei getSamples() const = 0;
 
 	GLuint getRedSize() const;
@@ -77,7 +76,6 @@
 	virtual GLsizei getWidth() const;
 	virtual GLsizei getHeight() const;
 	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
 	virtual GLsizei getSamples() const;
 
 private:
@@ -101,14 +99,12 @@
 	virtual GLsizei getWidth() const;
 	virtual GLsizei getHeight() const;
 	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
 	virtual GLsizei getSamples() const;
 
 protected:
 	GLsizei mWidth;
 	GLsizei mHeight;
 	GLenum format;
-	sw::Format internalFormat;
 	GLsizei mSamples;
 };
 
@@ -136,7 +132,6 @@
 	GLsizei getWidth() const;
 	GLsizei getHeight() const;
 	GLenum getFormat() const;
-	sw::Format getInternalFormat() const;
 	GLuint getRedSize() const;
 	GLuint getGreenSize() const;
 	GLuint getBlueSize() const;
@@ -155,7 +150,7 @@
 {
 public:
 	explicit Colorbuffer(egl::Image *renderTarget);
-	Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+	Colorbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	virtual ~Colorbuffer();
 
@@ -171,7 +166,7 @@
 {
 public:
 	explicit DepthStencilbuffer(egl::Image *depthStencil);
-	DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
+	DepthStencilbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	~DepthStencilbuffer();
 
@@ -187,7 +182,7 @@
 {
 public:
 	explicit Depthbuffer(egl::Image *depthStencil);
-	Depthbuffer(GLsizei width, GLsizei height, GLsizei samples);
+	Depthbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	virtual ~Depthbuffer();
 };
diff --git a/src/OpenGL/libGLES_CM/Texture.cpp b/src/OpenGL/libGLES_CM/Texture.cpp
index 9386f3f..d66c723 100644
--- a/src/OpenGL/libGLES_CM/Texture.cpp
+++ b/src/OpenGL/libGLES_CM/Texture.cpp
@@ -227,25 +227,25 @@
 	return image;
 }
 
-void Texture::setImage(egl::Context *context, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
+void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
 {
 	if(pixels && image)
 	{
-		egl::PixelStorageModes unpackParameters;
+		gl::PixelStorageModes unpackParameters;
 		unpackParameters.alignment = unpackAlignment;
-		image->loadImageData(context, 0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackParameters, pixels);
+		image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackParameters, pixels);
 	}
 }
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
 {
-	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with egl::ComputeCompressedSize() at the API level
+	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
 	}
 }
 
-void Texture::subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
+void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
 {
 	if(!image)
 	{
@@ -269,9 +269,9 @@
 
 	if(pixels)
 	{
-		egl::PixelStorageModes unpackParameters;
+		gl::PixelStorageModes unpackParameters;
 		unpackParameters.alignment = unpackAlignment;
-		image->loadImageData(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels);
+		image->loadImageData(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels);
 	}
 }
 
@@ -292,7 +292,7 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with egl::ComputeCompressedSize() at the API level
+	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
 	}
@@ -426,18 +426,12 @@
 	return image[level] ? image[level]->getHeight() : 0;
 }
 
-GLenum Texture2D::getFormat(GLenum target, GLint level) const
+GLint Texture2D::getFormat(GLenum target, GLint level) const
 {
 	ASSERT(target == GL_TEXTURE_2D);
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-GLenum Texture2D::getType(GLenum target, GLint level) const
-{
-	ASSERT(target == GL_TEXTURE_2D);
-	return image[level] ? image[level]->getType() : GL_NONE;
-}
-
 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
 {
 	ASSERT(target == GL_TEXTURE_2D);
@@ -457,37 +451,25 @@
 	return level - 1;
 }
 
-void Texture2D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
 	if(image[level])
 	{
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, type);
+	image[level] = egl::Image::create(this, width, height, internalformat);
 
 	if(!image[level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackAlignment, pixels, image[level]);
+	Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
 }
 
 void Texture2D::bindTexImage(gl::Surface *surface)
 {
-	switch(surface->getInternalFormat())
-	{
-	case sw::FORMAT_A8R8G8B8:
-	case sw::FORMAT_A8B8G8R8:
-	case sw::FORMAT_X8B8G8R8:
-	case sw::FORMAT_X8R8G8B8:
-		break;
-	default:
-		UNIMPLEMENTED();
-		return;
-	}
-
 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
 	{
 		if(image[level])
@@ -522,7 +504,7 @@
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, format);
 
 	if(!image[level])
 	{
@@ -532,9 +514,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[level]);
 }
 
-void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
+	Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
 }
 
 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
@@ -557,7 +539,7 @@
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, format);
 
 	if(!image[level])
 	{
@@ -662,11 +644,6 @@
 			return false;
 		}
 
-		if(image[level]->getType() != image[0]->getType())
-		{
-			return false;
-		}
-
 		if(image[level]->getWidth() != std::max(1, width >> level))
 		{
 			return false;
@@ -707,7 +684,7 @@
 			image[i]->release();
 		}
 
-		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
+		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat());
 
 		if(!image[i])
 		{
diff --git a/src/OpenGL/libGLES_CM/Texture.h b/src/OpenGL/libGLES_CM/Texture.h
index c66ed19..d823c61 100644
--- a/src/OpenGL/libGLES_CM/Texture.h
+++ b/src/OpenGL/libGLES_CM/Texture.h
@@ -76,8 +76,7 @@
 
 	virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
 	virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
-	virtual GLenum getFormat(GLenum target, GLint level) const = 0;
-	virtual GLenum getType(GLenum target, GLint level) const = 0;
+	virtual GLint getFormat(GLenum target, GLint level) const = 0;
 	virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;
 	virtual int getTopLevel() const = 0;
 
@@ -98,8 +97,8 @@
 protected:
 	~Texture() override;
 
-	void setImage(egl::Context *context, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
-	void subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
+	void setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
+	void subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
 	void setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image);
 	void subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);
 
@@ -134,14 +133,13 @@
 
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
+	GLint getFormat(GLenum target, GLint level) const override;
 	sw::Format getInternalFormat(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+	void setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
-	void subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+	void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 	void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
 	void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
 	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.cpp b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
index 93ff16a..f80aa89 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.cpp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
@@ -755,7 +755,7 @@
 			return error(GL_INVALID_ENUM);
 		}
 
-		if(imageSize != egl::ComputeCompressedSize(width, height, internalformat))
+		if(imageSize != gl::ComputeCompressedSize(width, height, internalformat))
 		{
 			return error(GL_INVALID_VALUE);
 		}
@@ -817,7 +817,7 @@
 
 	if(context)
 	{
-		if(imageSize != egl::ComputeCompressedSize(width, height, format))
+		if(imageSize != gl::ComputeCompressedSize(width, height, format))
 		{
 			return error(GL_INVALID_VALUE);
 		}
@@ -889,7 +889,7 @@
 		es1::Renderbuffer *source = framebuffer->getColorbuffer();
 		GLenum colorbufferFormat = source->getFormat();
 
-		// [OpenGL ES 2.0.24] table 3.9
+		// [OpenGL ES 1.1.12] table 3.9
 		switch(internalformat)
 		{
 		case GL_ALPHA:
@@ -936,6 +936,22 @@
 			return error(GL_INVALID_ENUM);
 		}
 
+		// Determine the sized internal format.
+		if(gl::GetBaseInternalFormat(colorbufferFormat) == internalformat)
+		{
+			internalformat = colorbufferFormat;
+		}
+		else if(GetRedSize(colorbufferFormat) == 8)
+		{
+			internalformat = gl::GetSizedInternalFormat(internalformat, GL_UNSIGNED_BYTE);
+		}
+		else
+		{
+			UNIMPLEMENTED();
+
+			return error(GL_INVALID_OPERATION);
+		}
+
 		if(target == GL_TEXTURE_2D)
 		{
 			es1::Texture2D *texture = context->getTexture2D();
@@ -1863,7 +1879,12 @@
 		{
 		case GL_RENDERBUFFER_WIDTH_OES:           *params = renderbuffer->getWidth();       break;
 		case GL_RENDERBUFFER_HEIGHT_OES:          *params = renderbuffer->getHeight();      break;
-		case GL_RENDERBUFFER_INTERNAL_FORMAT_OES: *params = renderbuffer->getFormat();      break;
+		case GL_RENDERBUFFER_INTERNAL_FORMAT_OES:
+			{
+				GLint internalformat = renderbuffer->getFormat();
+				*params = (internalformat == GL_NONE) ? GL_RGBA4_OES : internalformat;
+			}
+			break;
 		case GL_RENDERBUFFER_RED_SIZE_OES:        *params = renderbuffer->getRedSize();     break;
 		case GL_RENDERBUFFER_GREEN_SIZE_OES:      *params = renderbuffer->getGreenSize();   break;
 		case GL_RENDERBUFFER_BLUE_SIZE_OES:       *params = renderbuffer->getBlueSize();    break;
@@ -3428,9 +3449,6 @@
 
 		switch(internalformat)
 		{
-		case GL_DEPTH_COMPONENT16_OES:
-			context->setRenderbufferStorage(new es1::Depthbuffer(width, height, 0));
-			break;
 		case GL_RGBA4_OES:
 		case GL_RGB5_A1_OES:
 		case GL_RGB565_OES:
@@ -3438,11 +3456,14 @@
 		case GL_RGBA8_OES:
 			context->setRenderbufferStorage(new es1::Colorbuffer(width, height, internalformat, 0));
 			break;
+		case GL_DEPTH_COMPONENT16_OES:
+			context->setRenderbufferStorage(new es1::Depthbuffer(width, height, internalformat,  0));
+			break;
 		case GL_STENCIL_INDEX8_OES:
 			context->setRenderbufferStorage(new es1::Stencilbuffer(width, height, 0));
 			break;
 		case GL_DEPTH24_STENCIL8_OES:
-			context->setRenderbufferStorage(new es1::DepthStencilbuffer(width, height, 0));
+			context->setRenderbufferStorage(new es1::DepthStencilbuffer(width, height, internalformat, 0));
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4270,6 +4291,8 @@
 		return error(GL_INVALID_VALUE);
 	}
 
+	GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
+
 	es1::Context *context = es1::getContext();
 
 	if(context)
@@ -4296,7 +4319,7 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->setImage(context, level, width, height, format, type, context->getUnpackAlignment(), pixels);
+			texture->setImage(level, width, height, sizedInternalFormat, format, type, context->getUnpackAlignment(), pixels);
 		}
 		else UNREACHABLE(target);
 	}
@@ -4533,7 +4556,7 @@
 
 			if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, texture))
 			{
-				texture->subImage(context, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+				texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
 			}
 		}
 		else UNREACHABLE(target);
diff --git a/src/OpenGL/libGLES_CM/utilities.cpp b/src/OpenGL/libGLES_CM/utilities.cpp
index b0b110a..b2ba5eb 100644
--- a/src/OpenGL/libGLES_CM/utilities.cpp
+++ b/src/OpenGL/libGLES_CM/utilities.cpp
@@ -163,6 +163,236 @@
 		return false;
 	}
 
+	GLuint GetAlphaSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 1;
+		case GL_RGB565:         return 0;
+		case GL_R8:             return 0;
+		case GL_RG8:            return 0;
+		case GL_RGB8:           return 0;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 0;
+		case GL_RG16F:          return 0;
+		case GL_RGB16F:         return 0;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 0;
+		case GL_RG32F:          return 0;
+		case GL_RGB32F:         return 0;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 0;
+		case GL_R8I:            return 0;
+		case GL_R16UI:          return 0;
+		case GL_R16I:           return 0;
+		case GL_R32UI:          return 0;
+		case GL_R32I:           return 0;
+		case GL_RG8UI:          return 0;
+		case GL_RG8I:           return 0;
+		case GL_RG16UI:         return 0;
+		case GL_RG16I:          return 0;
+		case GL_RG32UI:         return 0;
+		case GL_RG32I:          return 0;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 2;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 2;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 0;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetRedSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 5;
+		case GL_RGB565:         return 5;
+		case GL_R8:             return 8;
+		case GL_RG8:            return 8;
+		case GL_RGB8:           return 8;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 16;
+		case GL_RG16F:          return 16;
+		case GL_RGB16F:         return 16;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 32;
+		case GL_RG32F:          return 32;
+		case GL_RGB32F:         return 32;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 8;
+		case GL_R8I:            return 8;
+		case GL_R16UI:          return 16;
+		case GL_R16I:           return 16;
+		case GL_R32UI:          return 32;
+		case GL_R32I:           return 32;
+		case GL_RG8UI:          return 8;
+		case GL_RG8I:           return 8;
+		case GL_RG16UI:         return 16;
+		case GL_RG16I:          return 16;
+		case GL_RG32UI:         return 32;
+		case GL_RG32I:          return 32;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 10;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 10;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 11;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetGreenSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 5;
+		case GL_RGB565:         return 6;
+		case GL_R8:             return 0;
+		case GL_RG8:            return 8;
+		case GL_RGB8:           return 8;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 0;
+		case GL_RG16F:          return 16;
+		case GL_RGB16F:         return 16;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 0;
+		case GL_RG32F:          return 32;
+		case GL_RGB32F:         return 32;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 0;
+		case GL_R8I:            return 0;
+		case GL_R16UI:          return 0;
+		case GL_R16I:           return 0;
+		case GL_R32UI:          return 0;
+		case GL_R32I:           return 0;
+		case GL_RG8UI:          return 8;
+		case GL_RG8I:           return 8;
+		case GL_RG16UI:         return 16;
+		case GL_RG16I:          return 16;
+		case GL_RG32UI:         return 32;
+		case GL_RG32I:          return 32;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 10;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 10;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 11;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetBlueSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 5;
+		case GL_RGB565:         return 5;
+		case GL_R8:             return 0;
+		case GL_RG8:            return 0;
+		case GL_RGB8:           return 8;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 0;
+		case GL_RG16F:          return 0;
+		case GL_RGB16F:         return 16;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 0;
+		case GL_RG32F:          return 0;
+		case GL_RGB32F:         return 32;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 0;
+		case GL_R8I:            return 0;
+		case GL_R16UI:          return 0;
+		case GL_R16I:           return 0;
+		case GL_R32UI:          return 0;
+		case GL_R32I:           return 0;
+		case GL_RG8UI:          return 0;
+		case GL_RG8I:           return 0;
+		case GL_RG16UI:         return 0;
+		case GL_RG16I:          return 0;
+		case GL_RG32UI:         return 0;
+		case GL_RG32I:          return 0;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 10;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 10;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 10;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetDepthSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8:        return 0;
+		case GL_DEPTH_COMPONENT16:     return 16;
+		case GL_DEPTH_COMPONENT24:     return 24;
+		case GL_DEPTH_COMPONENT32_OES: return 32;
+		case GL_DEPTH_COMPONENT32F:    return 32;
+		case GL_DEPTH24_STENCIL8:      return 24;
+		case GL_DEPTH32F_STENCIL8:     return 32;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetStencilSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8:        return 8;
+		case GL_DEPTH_COMPONENT16:     return 0;
+		case GL_DEPTH_COMPONENT24:     return 0;
+		case GL_DEPTH_COMPONENT32_OES: return 0;
+		case GL_DEPTH_COMPONENT32F:    return 0;
+		case GL_DEPTH24_STENCIL8:      return 8;
+		case GL_DEPTH32F_STENCIL8:     return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
 	bool IsAlpha(GLenum texFormat)
 	{
 		switch(texFormat)
@@ -549,145 +779,6 @@
 
 namespace sw2es
 {
-	unsigned int GetStencilSize(sw::Format stencilFormat)
-	{
-		switch(stencilFormat)
-		{
-		case sw::FORMAT_D24FS8:
-		case sw::FORMAT_D24S8:
-		case sw::FORMAT_D32FS8_TEXTURE:
-			return 8;
-	//	case sw::FORMAT_D24X4S4:
-	//		return 4;
-	//	case sw::FORMAT_D15S1:
-	//		return 1;
-	//	case sw::FORMAT_D16_LOCKABLE:
-		case sw::FORMAT_D32:
-		case sw::FORMAT_D24X8:
-		case sw::FORMAT_D32F_LOCKABLE:
-		case sw::FORMAT_D16:
-			return 0;
-	//	case sw::FORMAT_D32_LOCKABLE:  return 0;
-	//	case sw::FORMAT_S8_LOCKABLE:   return 8;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetAlphaSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 2;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-			return 1;
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-		case sw::FORMAT_R5G6B5:
-			return 0;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetRedSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-		case sw::FORMAT_R5G6B5:
-			return 5;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetGreenSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-			return 5;
-		case sw::FORMAT_R5G6B5:
-			return 6;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetBlueSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-		case sw::FORMAT_R5G6B5:
-			return 5;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetDepthSize(sw::Format depthFormat)
-	{
-		switch(depthFormat)
-		{
-	//	case sw::FORMAT_D16_LOCKABLE:   return 16;
-		case sw::FORMAT_D32:            return 32;
-	//	case sw::FORMAT_D15S1:          return 15;
-		case sw::FORMAT_D24S8:          return 24;
-		case sw::FORMAT_D24X8:          return 24;
-	//	case sw::FORMAT_D24X4S4:        return 24;
-		case sw::FORMAT_D16:            return 16;
-		case sw::FORMAT_D32F_LOCKABLE:  return 32;
-		case sw::FORMAT_D24FS8:         return 24;
-	//	case sw::FORMAT_D32_LOCKABLE:   return 32;
-	//	case sw::FORMAT_S8_LOCKABLE:    return 0;
-		case sw::FORMAT_D32FS8_TEXTURE: return 32;
-		default:                        return 0;
-		}
-	}
-
 	GLenum ConvertBackBufferFormat(sw::Format format)
 	{
 		switch(format)
diff --git a/src/OpenGL/libGLES_CM/utilities.h b/src/OpenGL/libGLES_CM/utilities.h
index ec2a257..4f55c86 100644
--- a/src/OpenGL/libGLES_CM/utilities.h
+++ b/src/OpenGL/libGLES_CM/utilities.h
@@ -42,6 +42,13 @@
 	bool IsDepthRenderable(GLenum internalformat);
 	bool IsStencilRenderable(GLenum internalformat);
 
+	GLuint GetAlphaSize(GLint internalformat);
+	GLuint GetRedSize(GLint internalformat);
+	GLuint GetGreenSize(GLint internalformat);
+	GLuint GetBlueSize(GLint internalformat);
+	GLuint GetDepthSize(GLint internalformat);
+	GLuint GetStencilSize(GLint internalformat);
+
 	bool IsAlpha(GLenum texFormat);
 	bool IsRGB(GLenum texFormat);
 	bool IsRGBA(GLenum texFormat);
@@ -63,7 +70,6 @@
 	sw::MipmapType ConvertMipMapFilter(GLenum minFilter);
 	sw::FilterType ConvertTextureFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
 	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  GLenum elementType, sw::DrawType &swPrimitiveType, int &primitiveCount);
-	sw::Format ConvertRenderbufferFormat(GLenum format);
 	sw::TextureStage::StageOperation ConvertCombineOperation(GLenum operation);
 	sw::TextureStage::SourceArgument ConvertSourceArgument(GLenum argument);
 	sw::TextureStage::ArgumentModifier ConvertSourceOperand(GLenum operand);
@@ -71,13 +77,6 @@
 
 namespace sw2es
 {
-	GLuint GetAlphaSize(sw::Format colorFormat);
-	GLuint GetRedSize(sw::Format colorFormat);
-	GLuint GetGreenSize(sw::Format colorFormat);
-	GLuint GetBlueSize(sw::Format colorFormat);
-	GLuint GetDepthSize(sw::Format depthFormat);
-	GLuint GetStencilSize(sw::Format stencilFormat);
-
 	GLenum ConvertBackBufferFormat(sw::Format format);
 	GLenum ConvertDepthStencilFormat(sw::Format format);
 }
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 6140e8b..50ef1ac 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -842,7 +842,7 @@
 	mState.unpackParameters.alignment = alignment;
 }
 
-const egl::PixelStorageModes &Context::getUnpackParameters() const
+const gl::PixelStorageModes &Context::getUnpackParameters() const
 {
 	return mState.unpackParameters;
 }
@@ -1568,7 +1568,7 @@
 GLsizei Context::getRequiredBufferSize(GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type) const
 {
 	GLsizei inputWidth = (mState.unpackParameters.rowLength == 0) ? width : mState.unpackParameters.rowLength;
-	GLsizei inputPitch = egl::ComputePitch(inputWidth, format, type, mState.unpackParameters.alignment);
+	GLsizei inputPitch = gl::ComputePitch(inputWidth, format, type, mState.unpackParameters.alignment);
 	GLsizei inputHeight = (mState.unpackParameters.imageHeight == 0) ? height : mState.unpackParameters.imageHeight;
 	return inputPitch * inputHeight * depth;
 }
@@ -3315,10 +3315,10 @@
 	}
 
 	GLsizei outputWidth = (mState.packParameters.rowLength > 0) ? mState.packParameters.rowLength : width;
-	GLsizei outputPitch = egl::ComputePitch(outputWidth, format, type, mState.packParameters.alignment);
+	GLsizei outputPitch = gl::ComputePitch(outputWidth, format, type, mState.packParameters.alignment);
 	GLsizei outputHeight = (mState.packParameters.imageHeight == 0) ? height : mState.packParameters.imageHeight;
 	pixels = getPixelPackBuffer() ? (unsigned char*)getPixelPackBuffer()->data() + (ptrdiff_t)pixels : (unsigned char*)pixels;
-	pixels = ((char*)pixels) + egl::ComputePackingOffset(format, type, outputWidth, outputHeight, mState.packParameters);
+	pixels = ((char*)pixels) + gl::ComputePackingOffset(format, type, outputWidth, outputHeight, mState.packParameters);
 
 	// Sized query sanity check
 	if(bufSize)
@@ -3350,7 +3350,7 @@
 	sw::Rect dstRect(0, 0, width, height);
 	rect.clip(0.0f, 0.0f, (float)renderTarget->getWidth(), (float)renderTarget->getHeight());
 
-	sw::Surface *externalSurface = sw::Surface::create(width, height, 1, egl::ConvertFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
+	sw::Surface *externalSurface = sw::Surface::create(width, height, 1, gl::ConvertReadFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
 	sw::SliceRectF sliceRect(rect);
 	sw::SliceRect dstSliceRect(dstRect);
 	device->blit(renderTarget, sliceRect, externalSurface, dstSliceRect, false, false, false);
diff --git a/src/OpenGL/libGLESv2/Context.h b/src/OpenGL/libGLESv2/Context.h
index c99143d..d6b3279 100644
--- a/src/OpenGL/libGLESv2/Context.h
+++ b/src/OpenGL/libGLESv2/Context.h
@@ -422,8 +422,8 @@
 	gl::BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][MAX_COMBINED_TEXTURE_IMAGE_UNITS];
 	gl::BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT];
 
-	egl::PixelStorageModes unpackParameters;
-	egl::PixelStorageModes packParameters;
+	gl::PixelStorageModes unpackParameters;
+	gl::PixelStorageModes packParameters;
 };
 
 class [[clang::lto_visibility_public]] Context : public egl::Context
@@ -533,7 +533,7 @@
 	void setUnpackSkipPixels(GLint skipPixels);
 	void setUnpackSkipRows(GLint skipRows);
 	void setUnpackSkipImages(GLint skipImages);
-	const egl::PixelStorageModes &getUnpackParameters() const;
+	const gl::PixelStorageModes &getUnpackParameters() const;
 
 	void setPackAlignment(GLint alignment);
 	void setPackRowLength(GLint rowLength);
diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index e82b252..6fcfba8 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -249,47 +249,6 @@
 		stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
 	}
 
-	egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
-	{
-		ASSERT(sw::Surface::isDepth(format) || sw::Surface::isStencil(format));
-
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		bool lockable = !sw::Surface::hasQuadLayout(format);
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
-	egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
 	void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
 	{
 		if(!bindResources() || !primitiveCount)
diff --git a/src/OpenGL/libGLESv2/Device.hpp b/src/OpenGL/libGLESv2/Device.hpp
index e81211d..1b0636b 100644
--- a/src/OpenGL/libGLESv2/Device.hpp
+++ b/src/OpenGL/libGLESv2/Device.hpp
@@ -58,8 +58,6 @@
 		void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);
 		void clearDepth(float z);
 		void clearStencil(unsigned int stencil, unsigned int mask);
-		egl::Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);
-		egl::Image *createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable);
 		void drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount);
 		void drawPrimitive(sw::DrawType type, unsigned int primiveCount);
 		void setPixelShader(const sw::PixelShader *shader);
diff --git a/src/OpenGL/libGLESv2/Framebuffer.cpp b/src/OpenGL/libGLESv2/Framebuffer.cpp
index 8c516d1..eaa7615 100644
--- a/src/OpenGL/libGLESv2/Framebuffer.cpp
+++ b/src/OpenGL/libGLESv2/Framebuffer.cpp
@@ -545,8 +545,6 @@
 		switch(colorbuffer->getFormat())
 		{
 		case GL_BGRA8_EXT:      return GL_BGRA_EXT;
-		case GL_BGRA4_ANGLE:    return GL_BGRA_EXT;
-		case GL_BGR5_A1_ANGLE:  return GL_BGRA_EXT;
 		case GL_RGBA4:          return GL_RGBA;
 		case GL_RGB5_A1:        return GL_RGBA;
 		case GL_RGBA8:          return GL_RGBA;
@@ -608,8 +606,6 @@
 		switch(colorbuffer->getFormat())
 		{
 		case GL_BGRA8_EXT:      return GL_UNSIGNED_BYTE;
-		case GL_BGRA4_ANGLE:    return GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT;
-		case GL_BGR5_A1_ANGLE:  return GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT;
 		case GL_RGBA4:          return GL_UNSIGNED_SHORT_4_4_4_4;
 		case GL_RGB5_A1:        return GL_UNSIGNED_SHORT_5_5_5_1;
 		case GL_RGBA8:          return GL_UNSIGNED_BYTE;
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.cpp b/src/OpenGL/libGLESv2/Renderbuffer.cpp
index f68c6f3..2e24b56 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.cpp
+++ b/src/OpenGL/libGLESv2/Renderbuffer.cpp
@@ -422,25 +422,26 @@
 	{
 		renderTarget->addRef();
 
-		sw::Format implementationFormat = renderTarget->getInternalFormat();
-		format = sw2es::ConvertBackBufferFormat(implementationFormat);
-
 		mWidth = renderTarget->getWidth();
 		mHeight = renderTarget->getHeight();
+		format = renderTarget->getFormat();
 		mSamples = renderTarget->getDepth() & ~1;
 	}
 }
 
 Colorbuffer::Colorbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mRenderTarget(nullptr)
 {
-	Device *device = getDevice();
-
-	sw::Format implementationFormat = es2sw::ConvertRenderbufferFormat(internalformat);
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mRenderTarget = device->createRenderTarget(width, height, implementationFormat, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mRenderTarget = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mRenderTarget)
 		{
@@ -499,41 +500,26 @@
 	{
 		depthStencil->addRef();
 
-		sw::Format implementationFormat = depthStencil->getInternalFormat();
-		format = sw2es::ConvertDepthStencilFormat(implementationFormat);
-
 		mWidth = depthStencil->getWidth();
 		mHeight = depthStencil->getHeight();
+		format = depthStencil->getFormat();
 		mSamples = depthStencil->getDepth() & ~1;
 	}
 }
 
 DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mDepthStencil(nullptr)
 {
-	format = internalformat;
-	sw::Format implementationFormat = sw::FORMAT_D24S8;
-	switch(internalformat)
-	{
-	case GL_STENCIL_INDEX8:        implementationFormat = sw::FORMAT_S8;     break;
-	case GL_DEPTH_COMPONENT24:     implementationFormat = sw::FORMAT_D24X8;  break;
-	case GL_DEPTH24_STENCIL8_OES:  implementationFormat = sw::FORMAT_D24S8;  break;
-	case GL_DEPTH32F_STENCIL8:     implementationFormat = sw::FORMAT_D32FS8; break;
-	case GL_DEPTH_COMPONENT16:     implementationFormat = sw::FORMAT_D16;    break;
-	case GL_DEPTH_COMPONENT32_OES: implementationFormat = sw::FORMAT_D32;    break;
-	case GL_DEPTH_COMPONENT32F:    implementationFormat = sw::FORMAT_D32F;   break;
-	default:
-		UNREACHABLE(internalformat);
-		format = GL_DEPTH24_STENCIL8_OES;
-		implementationFormat = sw::FORMAT_D24S8;
-	}
-
-	Device *device = getDevice();
-
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mDepthStencil = device->createDepthStencilSurface(width, height, implementationFormat, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mDepthStencil = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mDepthStencil)
 		{
@@ -544,6 +530,7 @@
 
 	mWidth = width;
 	mHeight = height;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.h b/src/OpenGL/libGLESv2/Renderbuffer.h
index f035d50..7a48fc8 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.h
+++ b/src/OpenGL/libGLESv2/Renderbuffer.h
@@ -27,10 +27,6 @@
 
 namespace es2
 {
-// Sized internal formats corresponding to GL_BGRA_EXT/GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT and
-// GL_BGRA_EXT/GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT format/type combinations, respectively.
-const GLint GL_BGRA4_ANGLE = 0x6ABC;
-const GLint GL_BGR5_A1_ANGLE = 0x6ABD;
 
 class Texture2D;
 class Texture3D;
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index 302320f..3d01ee5 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -333,25 +333,25 @@
 	return image;
 }
 
-void Texture::setImage(egl::Context *context, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
+void Texture::setImage(GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
 {
 	if(pixels && image)
 	{
 		GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
-		image->loadImageData(context, 0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackParameters, pixels);
+		image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackParameters, pixels);
 	}
 }
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
 {
-	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with egl::ComputeCompressedSize() at the API level
+	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels);
 	}
 }
 
-void Texture::subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
+void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
 {
 	if(!image)
 	{
@@ -360,7 +360,7 @@
 
 	if(pixels && width > 0 && height > 0 && depth > 0)
 	{
-		image->loadImageData(context, xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels);
+		image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels);
 	}
 }
 
@@ -371,7 +371,7 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with egl::ComputeCompressedSize() at the API level
+	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
 	}
@@ -515,12 +515,6 @@
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-GLenum Texture2D::getType(GLenum target, GLint level) const
-{
-	ASSERT(target == getTarget());
-	return image[level] ? image[level]->getType() : GL_NONE;
-}
-
 int Texture2D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
@@ -534,37 +528,25 @@
 	return level - 1;
 }
 
-void Texture2D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels)
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
 	if(image[level])
 	{
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, internalformat, type);
+	image[level] = egl::Image::create(this, width, height, internalformat);
 
 	if(!image[level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackParameters, pixels, image[level]);
+	Texture::setImage(format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture2D::bindTexImage(gl::Surface *surface)
 {
-	switch(surface->getInternalFormat())
-	{
-	case sw::FORMAT_A8R8G8B8:
-	case sw::FORMAT_A8B8G8R8:
-	case sw::FORMAT_X8B8G8R8:
-	case sw::FORMAT_X8R8G8B8:
-		break;
-	default:
-		UNIMPLEMENTED();
-		return;
-	}
-
 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
 	{
 		if(image[level])
@@ -599,8 +581,7 @@
 		image[level]->release();
 	}
 
-	GLint sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, format);
 
 	if(!image[level])
 	{
@@ -610,9 +591,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[level]);
 }
 
-void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels)
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[level]);
+	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
@@ -620,7 +601,7 @@
 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
 }
 
-void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
+void Texture2D::copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
 	egl::Image *renderTarget = source->getRenderTarget();
 
@@ -635,8 +616,7 @@
 		image[level]->release();
 	}
 
-	GLint sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, internalformat);
 
 	if(!image[level])
 	{
@@ -755,11 +735,6 @@
 			return false;
 		}
 
-		if(image[level]->getType() != image[mBaseLevel]->getType())
-		{
-			return false;
-		}
-
 		int i = level - mBaseLevel;
 
 		if(image[level]->getWidth() != std::max(1, width >> i))
@@ -801,7 +776,7 @@
 			image[i]->release();
 		}
 
-		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), image[mBaseLevel]->getFormat(), image[mBaseLevel]->getType());
+		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), image[mBaseLevel]->getFormat());
 
 		if(!image[i])
 		{
@@ -997,12 +972,6 @@
 	return image[face][level] ? image[face][level]->getFormat() : 0;
 }
 
-GLenum TextureCubeMap::getType(GLenum target, GLint level) const
-{
-	int face = CubeFaceIndex(target);
-	return image[face][level] ? image[face][level]->getType() : 0;
-}
-
 int TextureCubeMap::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
@@ -1025,9 +994,8 @@
 		image[face][level]->release();
 	}
 
-	GLint sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
 	int border = (egl::getClientVersion() >= 3) ? 1 : 0;
-	image[face][level] = egl::Image::create(this, width, height, 1, border, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[face][level] = egl::Image::create(this, width, height, 1, border, format);
 
 	if(!image[face][level])
 	{
@@ -1037,9 +1005,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[face][level]);
 }
 
-void TextureCubeMap::subImage(egl::Context *context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels)
+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[CubeFaceIndex(target)][level]);
+	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[CubeFaceIndex(target)][level]);
 }
 
 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
@@ -1095,8 +1063,7 @@
 	{
 		if(image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getWidth() ||
 		   image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getHeight() ||
-		   image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() ||
-		   image[face][mBaseLevel]->getType()   != image[0][mBaseLevel]->getType())
+		   image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat())
 		{
 			return false;
 		}
@@ -1135,11 +1102,6 @@
 				return false;
 			}
 
-			if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
-			{
-				return false;
-			}
-
 			int i = level - mBaseLevel;
 
 			if(image[face][level]->getWidth() != std::max(1, size >> i))
@@ -1230,7 +1192,7 @@
 	UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
 }
 
-void TextureCubeMap::setImage(egl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels)
+void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
 	int face = CubeFaceIndex(target);
 
@@ -1240,17 +1202,17 @@
 	}
 
 	int border = (egl::getClientVersion() >= 3) ? 1 : 0;
-	image[face][level] = egl::Image::create(this, width, height, 1, border, internalformat, type);
+	image[face][level] = egl::Image::create(this, width, height, 1, border, internalformat);
 
 	if(!image[face][level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackParameters, pixels, image[face][level]);
+	Texture::setImage(format, type, unpackParameters, pixels, image[face][level]);
 }
 
-void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
 	egl::Image *renderTarget = source->getRenderTarget();
 
@@ -1267,9 +1229,8 @@
 		image[face][level]->release();
 	}
 
-	GLint sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
 	int border = (egl::getClientVersion() >= 3) ? 1 : 0;
-	image[face][level] = egl::Image::create(this, width, height, 1, border, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[face][level] = egl::Image::create(this, width, height, 1, border, internalformat);
 
 	if(!image[face][level])
 	{
@@ -1351,7 +1312,7 @@
 			}
 
 			int border = (egl::getClientVersion() >= 3) ? 1 : 0;
-			image[f][i] = egl::Image::create(this, std::max(image[f][mBaseLevel]->getWidth() >> i, 1), std::max(image[f][mBaseLevel]->getHeight() >> i, 1), 1, border, image[f][mBaseLevel]->getFormat(), image[f][mBaseLevel]->getType());
+			image[f][i] = egl::Image::create(this, std::max(image[f][mBaseLevel]->getWidth() >> i, 1), std::max(image[f][mBaseLevel]->getHeight() >> i, 1), 1, border, image[f][mBaseLevel]->getFormat());
 
 			if(!image[f][i])
 			{
@@ -1520,12 +1481,6 @@
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-GLenum Texture3D::getType(GLenum target, GLint level) const
-{
-	ASSERT(target == getTarget());
-	return image[level] ? image[level]->getType() : GL_NONE;
-}
-
 int Texture3D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
@@ -1539,21 +1494,21 @@
 	return level - 1;
 }
 
-void Texture3D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels)
+void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
 	if(image[level])
 	{
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat, type);
+	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat);
 
 	if(!image[level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackParameters, pixels, image[level]);
+	Texture::setImage(format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture3D::releaseTexImage()
@@ -1568,8 +1523,7 @@
 		image[level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, depth, 0, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, depth, 0, format);
 
 	if(!image[level])
 	{
@@ -1579,9 +1533,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[level]);
 }
 
-void Texture3D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels)
+void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels, image[level]);
+	Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
@@ -1589,7 +1543,7 @@
 	Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
 }
 
-void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source)
+void Texture3D::copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source)
 {
 	egl::Image *renderTarget = source->getRenderTarget();
 
@@ -1604,8 +1558,7 @@
 		image[level]->release();
 	}
 
-	GLint sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, depth, 0, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat);
 
 	if(!image[level])
 	{
@@ -1726,11 +1679,6 @@
 			return false;
 		}
 
-		if(image[level]->getType() != image[mBaseLevel]->getType())
-		{
-			return false;
-		}
-
 		int i = level - mBaseLevel;
 
 		if(image[level]->getWidth() != std::max(1, width >> i))
@@ -1778,7 +1726,7 @@
 			image[i]->release();
 		}
 
-		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), std::max(image[mBaseLevel]->getDepth() >> i, 1), 0, image[mBaseLevel]->getFormat(), image[mBaseLevel]->getType());
+		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), std::max(image[mBaseLevel]->getDepth() >> i, 1), 0, image[mBaseLevel]->getFormat());
 
 		if(!image[i])
 		{
@@ -1875,7 +1823,7 @@
 
 		GLsizei w = std::max(image[mBaseLevel]->getWidth() >> i, 1);
 		GLsizei h = std::max(image[mBaseLevel]->getHeight() >> i, 1);
-		image[i] = egl::Image::create(this, w, h, depth, 0, image[mBaseLevel]->getFormat(), image[mBaseLevel]->getType());
+		image[i] = egl::Image::create(this, w, h, depth, 0, image[mBaseLevel]->getFormat());
 
 		if(!image[i])
 		{
@@ -1921,7 +1869,9 @@
 		return nullptr;
 	}
 
-	return egl::Image::create(width, height, format, multiSampleDepth, false);
+	GLenum internalformat = sw2es::ConvertBackBufferFormat(format);
+
+	return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
 }
 
 NO_SANITIZE_FUNCTION egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
@@ -1957,7 +1907,9 @@
 		UNREACHABLE(format);
 	}
 
-	egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
+	GLenum internalformat = sw2es::ConvertDepthStencilFormat(format);
+
+	egl::Image *surface = egl::Image::create(width, height, internalformat, multiSampleDepth, lockable);
 
 	if(!surface)
 	{
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index 246affe..b33c1bc 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -94,7 +94,6 @@
 	virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
 	virtual GLsizei getDepth(GLenum target, GLint level) const;
 	virtual GLenum getFormat(GLenum target, GLint level) const = 0;
-	virtual GLenum getType(GLenum target, GLint level) const = 0;
 	virtual int getTopLevel() const = 0;
 
 	virtual bool isSamplerComplete() const = 0;
@@ -112,8 +111,8 @@
 protected:
 	~Texture() override;
 
-	void setImage(egl::Context *context, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image);
-	void subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image);
+	void setImage(GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image);
+	void subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image);
 	void setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image);
 	void subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);
 
@@ -157,14 +156,13 @@
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
 	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels);
+	void setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
-	void subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels);
+	void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
-	void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
+	void copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
 	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source) override;
 
 	void setSharedImage(egl::Image *image);
@@ -223,15 +221,14 @@
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
 	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels);
+	void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
 
-	void subImage(egl::Context *context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels);
+	void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
-	void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
+	void copyImage(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
 	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source) override;
 
 	bool isSamplerComplete() const override;
@@ -285,14 +282,13 @@
 	GLsizei getHeight(GLenum target, GLint level) const override;
 	GLsizei getDepth(GLenum target, GLint level) const override;
 	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels);
+	void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
-	void subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::PixelStorageModes &unpackParameters, const void *pixels);
+	void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
-	void copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source);
+	void copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source);
 	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
 
 	void setSharedImage(egl::Image *image);
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 90fd752..b14dbcf 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -789,11 +789,17 @@
 			return error(GL_INVALID_ENUM);
 		}
 
-		if(imageSize != egl::ComputeCompressedSize(width, height, internalformat))
+		if(imageSize != gl::ComputeCompressedSize(width, height, internalformat))
 		{
 			return error(GL_INVALID_VALUE);
 		}
 
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NONE)
+		{
+			return error(validationError);
+		}
+
 		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
 			es2::Texture2D *texture = context->getTexture2D(target);
@@ -803,15 +809,9 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
-			if(validationError != GL_NONE)
-			{
-				return error(validationError);
-			}
-
 			texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
 		}
-		else
+		else if(es2::IsCubemapTextureTarget(target))
 		{
 			es2::TextureCubeMap *texture = context->getTextureCubeMap();
 
@@ -820,27 +820,9 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			switch(target)
-			{
-			case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-			case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-			case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-			case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-				{
-					GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
-					if(validationError != GL_NONE)
-					{
-						return error(validationError);
-					}
-
-					texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
-				}
-				break;
-			default: UNREACHABLE(target);
-			}
+			texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
 		}
+		else UNREACHABLE(target);
 	}
 }
 
@@ -867,7 +849,7 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, format))
+	if(imageSize != gl::ComputeCompressedSize(width, height, format))
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -882,6 +864,12 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NONE)
+		{
+			return error(validationError);
+		}
+
 		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
 			es2::Texture2D *texture = context->getTexture2D(target);
@@ -892,12 +880,6 @@
 				return error(validationError);
 			}
 
-			validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
-			if(validationError != GL_NONE)
-			{
-				return error(validationError);
-			}
-
 			texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
@@ -910,12 +892,6 @@
 				return error(validationError);
 			}
 
-			validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
-			if(validationError != GL_NONE)
-			{
-				return error(validationError);
-			}
-
 			texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
 		}
 		else UNREACHABLE(target);
@@ -989,6 +965,25 @@
 
 		GLenum colorbufferFormat = source->getFormat();
 
+		// Determine the sized internal format.
+		if(gl::IsUnsizedInternalFormat(internalformat))
+		{
+			if(gl::GetBaseInternalFormat(colorbufferFormat) == internalformat)
+			{
+				internalformat = colorbufferFormat;
+			}
+			else if(GetRedSize(colorbufferFormat) == 8)
+			{
+				internalformat = gl::GetSizedInternalFormat(internalformat, GL_UNSIGNED_BYTE);
+			}
+			else
+			{
+				UNIMPLEMENTED();
+
+				return error(GL_INVALID_OPERATION);
+			}
+		}
+
 		if(!ValidateCopyFormats(internalformat, colorbufferFormat))
 		{
 			return;
@@ -4962,7 +4957,7 @@
 			}
 		}
 
-		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, context->getClientVersion());
+		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, context->getClientVersion());
 		if(validationError != GL_NONE)
 		{
 			return error(validationError);
@@ -5004,7 +4999,7 @@
 			return error(GL_INVALID_ENUM);
 		}
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
+		GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
 
 		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
 		if(validationError != GL_NONE)
@@ -5021,7 +5016,7 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->setImage(context, level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
+			texture->setImage(level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 		}
 		else
 		{
@@ -5032,7 +5027,7 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->setImage(context, target, level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
+			texture->setImage(target, level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 		}
 	}
 }
@@ -5389,7 +5384,7 @@
 				return error(validationError);
 			}
 
-			texture->subImage(context, level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
+			texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
 		{
@@ -5407,7 +5402,7 @@
 				return error(validationError);
 			}
 
-			texture->subImage(context, target, level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
+			texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
 		}
 		else UNREACHABLE(target);
 	}
@@ -6210,7 +6205,7 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	GLenum validationError = ValidateTextureFormatType(format, type, internalformat, egl::getClientVersion());
+	GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, egl::getClientVersion());
 	if(validationError != GL_NONE)
 	{
 		return error(validationError);
@@ -6249,8 +6244,8 @@
 			return error(validationError);
 		}
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
-		texture->setImage(context, level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
+		GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
+		texture->setImage(level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -6269,11 +6264,6 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateTextureFormatType(format, type, format, egl::getClientVersion()))
-	{
-		return;
-	}
-
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
 	{
 		return error(GL_INVALID_VALUE);
@@ -6302,7 +6292,7 @@
 			return error(validationError);
 		}
 
-		texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
+		texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -6385,7 +6375,7 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
+	if(imageSize != gl::ComputeCompressedSize(width, height, internalformat) * depth)
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -6401,7 +6391,7 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
 
 		if(validationError != GL_NONE)
 		{
@@ -6442,7 +6432,7 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, format) * depth)
+	if(imageSize != gl::ComputeCompressedSize(width, height, format) * depth)
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -6458,7 +6448,7 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
 		if(validationError != GL_NONE)
 		{
 			return error(validationError);
diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index 0af7b65..e6dfcb5 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -34,15 +34,6 @@
 
 using namespace es2;
 
-typedef std::pair<GLenum, GLenum> InternalFormatTypePair;
-typedef std::map<InternalFormatTypePair, GLenum> FormatMap;
-
-// A helper function to insert data into the format map with fewer characters.
-static void InsertFormatMapping(FormatMap& map, GLenum internalformat, GLenum format, GLenum type)
-{
-	map[InternalFormatTypePair(internalformat, type)] = format;
-}
-
 static bool validImageSize(GLint level, GLsizei width, GLsizei height)
 {
 	if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
@@ -53,238 +44,6 @@
 	return true;
 }
 
-static FormatMap BuildFormatMap3D()
-{
-	FormatMap map;
-
-	//                       Internal format | Format | Type
-	InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
-	InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
-	InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
-	InsertFormatMapping(map, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_R8, GL_RED, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_R8_SNORM, GL_RED, GL_BYTE);
-	InsertFormatMapping(map, GL_R16F, GL_RED, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_R16F, GL_RED, GL_FLOAT);
-	InsertFormatMapping(map, GL_R32F, GL_RED, GL_FLOAT);
-	InsertFormatMapping(map, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_R8I, GL_RED_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_R16I, GL_RED_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_R32I, GL_RED_INTEGER, GL_INT);
-	InsertFormatMapping(map, GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RG8_SNORM, GL_RG, GL_BYTE);
-	InsertFormatMapping(map, GL_RG16F, GL_RG, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RG16F, GL_RG, GL_FLOAT);
-	InsertFormatMapping(map, GL_RG32F, GL_RG, GL_FLOAT);
-	InsertFormatMapping(map, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RG8I, GL_RG_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_RG16I, GL_RG_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_RG32I, GL_RG_INTEGER, GL_INT);
-	InsertFormatMapping(map, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
-	InsertFormatMapping(map, GL_RGB8_SNORM, GL_RGB, GL_BYTE);
-	InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV);
-	InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV);
-	InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB16F, GL_RGB, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RGB16F, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB32F, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_RGB32I, GL_RGB_INTEGER, GL_INT);
-	InsertFormatMapping(map, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
-	InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatMapping(map, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE);
-	InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
-	InsertFormatMapping(map, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatMapping(map, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RGBA16F, GL_RGBA, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGBA32F, GL_RGBA, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatMapping(map, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT);
-
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT);
-	InsertFormatMapping(map, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
-	InsertFormatMapping(map, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
-
-	return map;
-}
-
-static bool ValidateType3D(GLenum type)
-{
-	switch(type)
-	{
-	case GL_UNSIGNED_BYTE:
-	case GL_BYTE:
-	case GL_UNSIGNED_SHORT:
-	case GL_SHORT:
-	case GL_UNSIGNED_INT:
-	case GL_INT:
-	case GL_HALF_FLOAT:
-	case GL_FLOAT:
-	case GL_UNSIGNED_SHORT_5_6_5:
-	case GL_UNSIGNED_SHORT_4_4_4_4:
-	case GL_UNSIGNED_SHORT_5_5_5_1:
-	case GL_UNSIGNED_INT_2_10_10_10_REV:
-	case GL_UNSIGNED_INT_10F_11F_11F_REV:
-	case GL_UNSIGNED_INT_5_9_9_9_REV:
-	case GL_UNSIGNED_INT_24_8:
-	case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-		return true;
-	default:
-		break;
-	}
-	return false;
-}
-
-static bool ValidateFormat3D(GLenum format)
-{
-	switch(format)
-	{
-	case GL_RED:
-	case GL_RG:
-	case GL_RGB:
-	case GL_RGBA:
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_STENCIL:
-	case GL_LUMINANCE_ALPHA:
-	case GL_LUMINANCE:
-	case GL_ALPHA:
-	case GL_RED_INTEGER:
-	case GL_RG_INTEGER:
-	case GL_RGB_INTEGER:
-	case GL_RGBA_INTEGER:
-		return true;
-	default:
-		break;
-	}
-	return false;
-}
-
-static bool ValidateInternalFormat3D(GLenum internalformat, GLenum format, GLenum type)
-{
-	static const FormatMap formatMap = BuildFormatMap3D();
-	FormatMap::const_iterator iter = formatMap.find(InternalFormatTypePair(internalformat, type));
-	if(iter != formatMap.end())
-	{
-		return iter->second == format;
-	}
-	return false;
-}
-
-typedef std::map<GLenum, GLenum> FormatMapStorage;
-
-// A helper function to insert data into the format map with fewer characters.
-static void InsertFormatStorageMapping(FormatMapStorage& map, GLenum internalformat, GLenum type)
-{
-	map[internalformat] = type;
-}
-
-static FormatMapStorage BuildFormatMapStorage2D()
-{
-	FormatMapStorage map;
-
-	//                              Internal format | Type
-	InsertFormatStorageMapping(map, GL_R8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_R8_SNORM, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_R16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_R32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_R8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_R8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_R16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_R16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_R32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_R32I, GL_INT);
-	InsertFormatStorageMapping(map, GL_RG8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RG8_SNORM, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RG16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_RG32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_RG8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RG8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RG16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_RG16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_RG32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_RG32I, GL_INT);
-	InsertFormatStorageMapping(map, GL_RGB8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_SRGB8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5);
-	InsertFormatStorageMapping(map, GL_RGB8_SNORM, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV);
-	InsertFormatStorageMapping(map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV);
-	InsertFormatStorageMapping(map, GL_RGB16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGB32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGB8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_RGB16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_RGB32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_RGB32I, GL_INT);
-	InsertFormatStorageMapping(map, GL_RGBA8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGBA8_SNORM, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1);
-	InsertFormatStorageMapping(map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4);
-	InsertFormatStorageMapping(map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatStorageMapping(map, GL_RGBA16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGBA32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGBA8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGBA8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatStorageMapping(map, GL_RGBA16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_RGBA16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_RGBA32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_RGBA32I, GL_INT);
-
-	InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8);
-	InsertFormatStorageMapping(map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
-
-	return map;
-}
-
-static bool GetStorageType(GLenum internalformat, GLenum& type)
-{
-	static const FormatMapStorage formatMap = BuildFormatMapStorage2D();
-	FormatMapStorage::const_iterator iter = formatMap.find(internalformat);
-	if(iter != formatMap.end())
-	{
-		type = iter->second;
-		return true;
-	}
-	return false;
-}
-
 static bool ValidateQueryTarget(GLenum target)
 {
 	switch(target)
@@ -589,11 +348,6 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateType3D(type) || !ValidateFormat3D(format))
-	{
-		return error(GL_INVALID_ENUM);
-	}
-
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
 	{
 		return error(GL_INVALID_VALUE);
@@ -610,15 +364,16 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(!ValidateInternalFormat3D(internalformat, format, type))
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
 	{
+		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, context->getClientVersion());
+		if(validationError != GL_NONE)
+		{
+			return error(validationError);
+		}
+
 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
 
 		if(!texture)
@@ -626,14 +381,14 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLenum validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
+		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
 		if(validationError != GL_NONE)
 		{
 			return error(validationError);
 		}
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
-		texture->setImage(context, level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
+		GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
+		texture->setImage(level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -653,11 +408,6 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateType3D(type) || !ValidateFormat3D(format))
-	{
-		return error(GL_INVALID_ENUM);
-	}
-
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
 	{
 		return error(GL_INVALID_VALUE);
@@ -669,7 +419,7 @@
 	}
 
 	es2::Context *context = es2::getContext();
-
+	
 	if(context)
 	{
 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
@@ -686,7 +436,7 @@
 			return error(validationError);
 		}
 
-		texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
+		texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -784,7 +534,7 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
+	if(imageSize != gl::ComputeCompressedSize(width, height, internalformat) * depth)
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -800,7 +550,7 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
 		if(validationError != GL_NONE)
 		{
 			return error(validationError);
@@ -841,7 +591,7 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, format) * depth)
+	if(imageSize != gl::ComputeCompressedSize(width, height, format) * depth)
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -887,7 +637,7 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
 		if(validationError != GL_NONE)
 		{
 			return error(validationError);
@@ -3854,12 +3604,10 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	GLenum type;
-	if(!GetStorageType(internalformat, type))
+	if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat, egl::getClientVersion()))
 	{
 		return error(GL_INVALID_ENUM);
 	}
-	GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
 
 	es2::Context *context = es2::getContext();
 
@@ -3875,10 +3623,10 @@
 				{
 					return error(GL_INVALID_OPERATION);
 				}
-	
+
 				for(int level = 0; level < levels; level++)
 				{
-					texture->setImage(context, level, width, height, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackParameters(), nullptr);
+					texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
 					width = std::max(1, (width / 2));
 					height = std::max(1, (height / 2));
 				}
@@ -3892,12 +3640,12 @@
 				{
 					return error(GL_INVALID_OPERATION);
 				}
-	
+
 				for(int level = 0; level < levels; level++)
 				{
 					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
 					{
-							texture->setImage(context, face, level, width, height, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackParameters(), nullptr);
+						texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
 					}
 					width = std::max(1, (width / 2));
 					height = std::max(1, (height / 2));
@@ -3921,12 +3669,10 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	GLenum type;
-	if(!GetStorageType(internalformat, type))
+	if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat, egl::getClientVersion()))
 	{
 		return error(GL_INVALID_ENUM);
 	}
-	GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
 
 	es2::Context *context = es2::getContext();
 
@@ -3940,16 +3686,16 @@
 				{
 					return error(GL_INVALID_OPERATION);
 				}
-	
+
 				es2::Texture3D *texture = context->getTexture3D();
 				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
 				{
 					return error(GL_INVALID_OPERATION);
 				}
-	
+
 				for(int level = 0; level < levels; level++)
 				{
-					texture->setImage(context, level, width, height, depth, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackParameters(), nullptr);
+					texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
 					width = std::max(1, (width / 2));
 					height = std::max(1, (height / 2));
 					depth = std::max(1, (depth / 2));
@@ -3963,18 +3709,18 @@
 				{
 					return error(GL_INVALID_OPERATION);
 				}
-	
+
 				es2::Texture3D *texture = context->getTexture2DArray();
 				if(!texture || texture->name == 0 || texture->getImmutableFormat())
 				{
 					return error(GL_INVALID_OPERATION);
 				}
-	
+
 				for(int level = 0; level < levels; level++)
 				{
 					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
 					{
-							texture->setImage(context, level, width, height, depth, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackParameters(), nullptr);
+						texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
 					}
 					width = std::max(1, (width / 2));
 					height = std::max(1, (height / 2));
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 6a0a417..c00f62d 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -29,145 +29,6 @@
 
 namespace es2
 {
-	// ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation
-	// can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid
-	// format and type combinations.
-
-	typedef std::pair<GLenum, GLenum> FormatTypePair;
-	typedef std::pair<FormatTypePair, GLint> FormatPair;
-	typedef std::map<FormatTypePair, GLenum> FormatMap;
-
-	// A helper function to insert data into the format map with fewer characters.
-	static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLint internalFormat)
-	{
-		map->insert(FormatPair(FormatTypePair(format, type), internalFormat));
-	}
-
-	FormatMap BuildFormatMap()
-	{
-		FormatMap map;
-
-		//                       | Format | Type | Internal format |
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8);
-		InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM);
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4);
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1);
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2);
-		InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F);
-		InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F);
-		InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F);
-
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI);
-
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8);
-		InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM);
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565);
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F);
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5);
-		InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F);
-		InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F);
-		InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F);
-
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I);
-
-		InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8);
-		InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM);
-		InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F);
-		InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F);
-		InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F);
-
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I);
-
-		InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8);
-		InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM);
-		InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F);
-		InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F);
-		InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F);
-
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I);
-
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT);
-
-		InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT);
-		InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLE);
-		InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLE);
-
-		InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8);
-		InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8);
-
-		InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16);
-		InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES);
-		InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F);
-
-		InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8);
-
-		InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8);
-		InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8);
-
-		return map;
-	}
-
-	GLint GetSizedInternalFormat(GLint internalformat, GLenum type)
-	{
-		switch(internalformat)
-		{
-		case GL_ALPHA:
-		case GL_LUMINANCE:
-		case GL_LUMINANCE_ALPHA:
-		case GL_RED:
-		case GL_RG:
-		case GL_RGB:
-		case GL_RGBA:
-		case GL_RED_INTEGER:
-		case GL_RG_INTEGER:
-		case GL_RGB_INTEGER:
-		case GL_RGBA_INTEGER:
-		case GL_BGRA_EXT:
-		case GL_DEPTH_COMPONENT:
-		case GL_DEPTH_STENCIL:
-		case GL_SRGB_EXT:
-		case GL_SRGB_ALPHA_EXT:
-			{
-				static const FormatMap formatMap = BuildFormatMap();
-				FormatMap::const_iterator iter = formatMap.find(FormatTypePair(internalformat, type));
-				return (iter != formatMap.end()) ? iter->second : GL_NONE;
-			}
-		default:
-			return internalformat;
-		}
-	}
 
 	unsigned int UniformComponentCount(GLenum type)
 	{
@@ -462,9 +323,9 @@
 		return -1;
 	}
 
-	bool IsCompressed(GLenum format, GLint clientVersion)
+	bool IsCompressed(GLint internalformat, GLint clientVersion)
 	{
-		switch(format)
+		switch(internalformat)
 		{
 		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
@@ -517,6 +378,76 @@
 		}
 	}
 
+	bool IsSizedInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_R8:
+		case GL_R8UI:
+		case GL_R8I:
+		case GL_R16UI:
+		case GL_R16I:
+		case GL_R32UI:
+		case GL_R32I:
+		case GL_RG8:
+		case GL_RG8UI:
+		case GL_RG8I:
+		case GL_RG16UI:
+		case GL_RG16I:
+		case GL_RG32UI:
+		case GL_RG32I:
+		case GL_SRGB8_ALPHA8:
+		case GL_RGB8UI:
+		case GL_RGB8I:
+		case GL_RGB16UI:
+		case GL_RGB16I:
+		case GL_RGB32UI:
+		case GL_RGB32I:
+		case GL_RG8_SNORM:
+		case GL_R8_SNORM:
+		case GL_RGB10_A2:
+		case GL_RGBA8UI:
+		case GL_RGBA8I:
+		case GL_RGB10_A2UI:
+		case GL_RGBA16UI:
+		case GL_RGBA16I:
+		case GL_RGBA32I:
+		case GL_RGBA32UI:
+		case GL_RGBA4:
+		case GL_RGB5_A1:
+		case GL_RGB565:
+		case GL_RGB8:
+		case GL_RGBA8:
+		case GL_BGRA8_EXT:   // GL_APPLE_texture_format_BGRA8888
+		case GL_R16F:
+		case GL_RG16F:
+		case GL_R11F_G11F_B10F:
+		case GL_RGB16F:
+		case GL_RGBA16F:
+		case GL_R32F:
+		case GL_RG32F:
+		case GL_RGB32F:
+		case GL_RGBA32F:
+		case GL_DEPTH_COMPONENT24:
+		case GL_DEPTH_COMPONENT32_OES:
+		case GL_DEPTH_COMPONENT32F:
+		case GL_DEPTH32F_STENCIL8:
+		case GL_DEPTH_COMPONENT16:
+		case GL_STENCIL_INDEX8:
+		case GL_DEPTH24_STENCIL8_OES:
+		case GL_RGBA8_SNORM:
+		case GL_SRGB8:
+		case GL_RGB8_SNORM:
+		case GL_RGB9_E5:
+			return true;
+		default:
+			return false;
+		}
+	}
+
 	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
 	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture, GLint clientVersion)
 	{
@@ -536,7 +467,7 @@
 		}
 		else if(!copy)   // CopyTexSubImage doesn't have format/type parameters.
 		{
-			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, clientVersion);
+			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target, clientVersion);
 			if(validationError != GL_NONE)
 			{
 				return validationError;
@@ -578,7 +509,7 @@
 		{
 			GLenum sizedInternalFormat = texture->getFormat(target, level);
 
-			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, clientVersion);
+			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target, clientVersion);
 			if(validationError != GL_NONE)
 			{
 				return validationError;
@@ -607,8 +538,26 @@
 
 	bool ValidateCopyFormats(GLenum textureFormat, GLenum colorbufferFormat)
 	{
-		GLenum baseTexureFormat = GetBaseInternalFormat(textureFormat);
-		GLenum baseColorbufferFormat = GetBaseInternalFormat(colorbufferFormat);
+		ASSERT(!gl::IsUnsizedInternalFormat(textureFormat));
+		ASSERT(!gl::IsUnsizedInternalFormat(colorbufferFormat));
+
+		if(GetColorComponentType(textureFormat) == GL_NONE)
+		{
+			return error(GL_INVALID_ENUM, false);
+		}
+
+		if(GetColorComponentType(colorbufferFormat) != GetColorComponentType(textureFormat))
+		{
+			return error(GL_INVALID_OPERATION, false);
+		}
+
+		if(GetColorEncoding(colorbufferFormat) != GetColorEncoding(textureFormat))
+		{
+			return error(GL_INVALID_OPERATION, false);
+		}
+
+		GLenum baseTexureFormat = gl::GetBaseInternalFormat(textureFormat);
+		GLenum baseColorbufferFormat = gl::GetBaseInternalFormat(colorbufferFormat);
 
 		// [OpenGL ES 2.0.24] table 3.9
 		// [OpenGL ES 3.0.5] table 3.16
@@ -824,7 +773,7 @@
 		return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target) || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_RECTANGLE_ARB;
 	}
 
-	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLint clientVersion)
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target, GLint clientVersion)
 	{
 		switch(type)
 		{
@@ -863,11 +812,26 @@
 		case GL_LUMINANCE:
 		case GL_LUMINANCE_ALPHA:
 		case GL_BGRA_EXT:          // GL_EXT_texture_format_BGRA8888
-		case GL_DEPTH_STENCIL:     // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
-		case GL_DEPTH_COMPONENT:   // GL_OES_depth_texture
 		case GL_RED_EXT:           // GL_EXT_texture_rg
 		case GL_RG_EXT:            // GL_EXT_texture_rg
 			break;
+		case GL_DEPTH_STENCIL:     // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
+		case GL_DEPTH_COMPONENT:   // GL_OES_depth_texture
+			switch(target)
+			{
+			case GL_TEXTURE_2D:
+			case GL_TEXTURE_2D_ARRAY:
+			case GL_TEXTURE_CUBE_MAP_POSITIVE_X:   // GL_OES_depth_texture_cube_map
+			case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+			case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+			case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+				break;
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
 		case GL_RED_INTEGER:
 		case GL_RG_INTEGER:
 		case GL_RGB_INTEGER:
@@ -883,93 +847,14 @@
 
 		if((GLenum)internalformat != format)
 		{
-			switch(internalformat)
+			if(gl::IsUnsizedInternalFormat(internalformat))
 			{
-			// Unsized internal formats:
-			case GL_ALPHA:
-			case GL_RGB:
-			case GL_RGBA:
-			case GL_LUMINANCE:
-			case GL_LUMINANCE_ALPHA:
-			case GL_BGRA_EXT:          // GL_EXT_texture_format_BGRA8888
-			case GL_DEPTH_STENCIL:     // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
-			case GL_DEPTH_COMPONENT:   // GL_OES_depth_texture
-			case GL_RED:               // = GL_RED_EXT in GL_EXT_texture_rg
-			case GL_RG:                // = GL_RG_EXT in GL_EXT_texture_rg
-				break;
-			case GL_RED_INTEGER:
-			case GL_RG_INTEGER:
-			case GL_RGB_INTEGER:
-			case GL_RGBA_INTEGER:
-				if(clientVersion < 3)
-				{
-					return GL_INVALID_ENUM;
-				}
-				break;
-			// Sized internal formats:
-			case GL_ALPHA8_EXT:
-			case GL_LUMINANCE8_ALPHA8_EXT:
-			case GL_LUMINANCE8_EXT:
-			case GL_R8:
-			case GL_R8UI:
-			case GL_R8I:
-			case GL_R16UI:
-			case GL_R16I:
-			case GL_R32UI:
-			case GL_R32I:
-			case GL_RG8:
-			case GL_RG8UI:
-			case GL_RG8I:
-			case GL_RG16UI:
-			case GL_RG16I:
-			case GL_RG32UI:
-			case GL_RG32I:
-			case GL_SRGB8_ALPHA8:
-			case GL_RGB8UI:
-			case GL_RGB8I:
-			case GL_RGB16UI:
-			case GL_RGB16I:
-			case GL_RGB32UI:
-			case GL_RGB32I:
-			case GL_RG8_SNORM:
-			case GL_R8_SNORM:
-			case GL_RGB10_A2:
-			case GL_RGBA8UI:
-			case GL_RGBA8I:
-			case GL_RGB10_A2UI:
-			case GL_RGBA16UI:
-			case GL_RGBA16I:
-			case GL_RGBA32I:
-			case GL_RGBA32UI:
-			case GL_RGBA4:
-			case GL_RGB5_A1:
-			case GL_RGB565:
-			case GL_RGB8:
-			case GL_RGBA8:
-			case GL_BGRA8_EXT:   // GL_APPLE_texture_format_BGRA8888
-			case GL_R16F:
-			case GL_RG16F:
-			case GL_R11F_G11F_B10F:
-			case GL_RGB16F:
-			case GL_RGBA16F:
-			case GL_R32F:
-			case GL_RG32F:
-			case GL_RGB32F:
-			case GL_RGBA32F:
-			case GL_DEPTH_COMPONENT24:
-			case GL_DEPTH_COMPONENT32_OES:
-			case GL_DEPTH_COMPONENT32F:
-			case GL_DEPTH32F_STENCIL8:
-			case GL_DEPTH_COMPONENT16:
-			case GL_STENCIL_INDEX8:
-			case GL_DEPTH24_STENCIL8_OES:
-			case GL_RGBA8_SNORM:
-			case GL_SRGB8:
-			case GL_RGB8_SNORM:
-			case GL_RGB9_E5:
-				break;
-			default:
-				return GL_INVALID_ENUM;
+				return GL_INVALID_OPERATION;
+			}
+
+			if(!IsSizedInternalFormat(internalformat))
+			{
+				return GL_INVALID_VALUE;
 			}
 		}
 
@@ -1267,93 +1152,6 @@
 		return 1;
 	}
 
-	GLenum GetBaseInternalFormat(GLint internalformat)
-	{
-		switch(internalformat)
-		{
-		// Unsized internal formats which are valid as the <internalformat> parameter of CopyTexImage.
-		case GL_RGB:
-		case GL_RGBA:
-		case GL_ALPHA:
-		case GL_LUMINANCE:
-		case GL_LUMINANCE_ALPHA:
-		case GL_RED_EXT:           // GL_EXT_texture_rg
-		case GL_RG_EXT:            // GL_EXT_texture_rg
-			return internalformat;
-
-		// [OpenGL ES 3.0 Table 3.13]
-		case GL_R8:       return GL_RED;
-		case GL_R8_SNORM: return GL_RED;
-		case GL_RG8:       return GL_RG;
-		case GL_RG8_SNORM: return GL_RG;
-		case GL_RGB8:       return GL_RGB;
-		case GL_RGB8_SNORM: return GL_RGB;
-		case GL_RGB565:     return GL_RGB;
-		case GL_RGBA4:        return GL_RGBA;
-		case GL_RGB5_A1:      return GL_RGBA;
-		case GL_RGBA8:        return GL_RGBA;
-		case GL_RGBA8_SNORM:  return GL_RGBA;
-		case GL_RGB10_A2:     return GL_RGBA;
-		case GL_RGB10_A2UI:   return GL_RGBA;
-		case GL_SRGB8:        return GL_RGB;
-		case GL_SRGB8_ALPHA8: return GL_RGBA;
-		case GL_R16F:    return GL_RED;
-		case GL_RG16F:   return GL_RG;
-		case GL_RGB16F:  return GL_RGB;
-		case GL_RGBA16F: return GL_RGBA;
-		case GL_R32F:    return GL_RED;
-		case GL_RG32F:   return GL_RG;
-		case GL_RGB32F:  return GL_RGB;
-		case GL_RGBA32F: return GL_RGBA;
-		case GL_R11F_G11F_B10F: return GL_RGB;
-		case GL_RGB9_E5:        return GL_RGB;
-		case GL_R8I:      return GL_RED;
-		case GL_R8UI:     return GL_RED;
-		case GL_R16I:     return GL_RED;
-		case GL_R16UI:    return GL_RED;
-		case GL_R32I:     return GL_RED;
-		case GL_R32UI:    return GL_RED;
-		case GL_RG8I:     return GL_RG;
-		case GL_RG8UI:    return GL_RG;
-		case GL_RG16I:    return GL_RG;
-		case GL_RG16UI:   return GL_RG;
-		case GL_RG32I:    return GL_RG;
-		case GL_RG32UI:   return GL_RG;
-		case GL_RGB8I:    return GL_RGB;
-		case GL_RGB8UI:   return GL_RGB;
-		case GL_RGB16I:   return GL_RGB;
-		case GL_RGB16UI:  return GL_RGB;
-		case GL_RGB32I:   return GL_RGB;
-		case GL_RGB32UI:  return GL_RGB;
-		case GL_RGBA8I:   return GL_RGBA;
-		case GL_RGBA8UI:  return GL_RGBA;
-		case GL_RGBA16I:  return GL_RGBA;
-		case GL_RGBA16UI: return GL_RGBA;
-		case GL_RGBA32I:  return GL_RGBA;
-		case GL_RGBA32UI: return GL_RGBA;
-
-		// GL_EXT_texture_storage
-		case GL_ALPHA8_EXT:            return GL_ALPHA;
-		case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA;
-		case GL_LUMINANCE8_EXT:        return GL_LUMINANCE;
-
-		case GL_BGRA8_EXT: return GL_BGRA_EXT;   // GL_APPLE_texture_format_BGRA8888
-
-		case GL_DEPTH_COMPONENT24:     return GL_DEPTH_COMPONENT;
-		case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT;
-		case GL_DEPTH_COMPONENT32F:    return GL_DEPTH_COMPONENT;
-		case GL_DEPTH_COMPONENT16:     return GL_DEPTH_COMPONENT;
-		case GL_DEPTH32F_STENCIL8:     return GL_DEPTH_STENCIL;
-		case GL_DEPTH24_STENCIL8:      return GL_DEPTH_STENCIL;
-		case GL_STENCIL_INDEX8:        return GL_STENCIL_INDEX_OES;
-		default:
-			UNREACHABLE(internalformat);
-			break;
-		}
-
-		return GL_NONE;
-	}
-
 	bool IsColorRenderable(GLint internalformat, GLint clientVersion)
 	{
 		if(IsCompressed(internalformat, clientVersion))
@@ -2295,64 +2093,6 @@
 
 		return true;
 	}
-
-	sw::Format ConvertRenderbufferFormat(GLenum format)
-	{
-		switch(format)
-		{
-		case GL_NONE:                 return sw::FORMAT_NULL;
-		case GL_RGBA4:
-		case GL_RGB5_A1:
-		case GL_RGBA8:                return sw::FORMAT_A8B8G8R8;
-		case GL_RGB565:               return sw::FORMAT_R5G6B5;
-		case GL_RGB8:                 return sw::FORMAT_X8B8G8R8;
-		case GL_DEPTH_COMPONENT16:
-		case GL_DEPTH_COMPONENT24:
-		case GL_STENCIL_INDEX8:
-		case GL_DEPTH24_STENCIL8_OES: return sw::FORMAT_D24S8;
-		case GL_DEPTH_COMPONENT32_OES:return sw::FORMAT_D32;
-		case GL_R8:                   return sw::FORMAT_R8;
-		case GL_RG8:                  return sw::FORMAT_G8R8;
-		case GL_R8I:                  return sw::FORMAT_R8I;
-		case GL_RG8I:                 return sw::FORMAT_G8R8I;
-		case GL_RGB8I:                return sw::FORMAT_X8B8G8R8I;
-		case GL_RGBA8I:               return sw::FORMAT_A8B8G8R8I;
-		case GL_R8UI:                 return sw::FORMAT_R8UI;
-		case GL_RG8UI:                return sw::FORMAT_G8R8UI;
-		case GL_RGB8UI:               return sw::FORMAT_X8B8G8R8UI;
-		case GL_RGBA8UI:              return sw::FORMAT_A8B8G8R8UI;
-		case GL_R16I:                 return sw::FORMAT_R16I;
-		case GL_RG16I:                return sw::FORMAT_G16R16I;
-		case GL_RGB16I:               return sw::FORMAT_X16B16G16R16I;
-		case GL_RGBA16I:              return sw::FORMAT_A16B16G16R16I;
-		case GL_R16UI:                return sw::FORMAT_R16UI;
-		case GL_RG16UI:               return sw::FORMAT_G16R16UI;
-		case GL_RGB16UI:              return sw::FORMAT_X16B16G16R16UI;
-		case GL_RGBA16UI:             return sw::FORMAT_A16B16G16R16UI;
-		case GL_R32I:                 return sw::FORMAT_R32I;
-		case GL_RG32I:                return sw::FORMAT_G32R32I;
-		case GL_RGB32I:               return sw::FORMAT_X32B32G32R32I;
-		case GL_RGBA32I:              return sw::FORMAT_A32B32G32R32I;
-		case GL_R32UI:                return sw::FORMAT_R32UI;
-		case GL_RG32UI:               return sw::FORMAT_G32R32UI;
-		case GL_RGB32UI:              return sw::FORMAT_X32B32G32R32UI;
-		case GL_RGBA32UI:             return sw::FORMAT_A32B32G32R32UI;
-		case GL_R16F:                 return sw::FORMAT_R16F;
-		case GL_RG16F:                return sw::FORMAT_G16R16F;
-		case GL_R11F_G11F_B10F:       return sw::FORMAT_X16B16G16R16F_UNSIGNED;
-		case GL_RGB16F:               return sw::FORMAT_X16B16G16R16F;
-		case GL_RGBA16F:              return sw::FORMAT_A16B16G16R16F;
-		case GL_R32F:                 return sw::FORMAT_R32F;
-		case GL_RG32F:                return sw::FORMAT_G32R32F;
-		case GL_RGB32F:               return sw::FORMAT_B32G32R32F;
-		case GL_RGBA32F:              return sw::FORMAT_A32B32G32R32F;
-		case GL_RGB10_A2:             return sw::FORMAT_A2B10G10R10;
-		case GL_RGB10_A2UI:           return sw::FORMAT_A2B10G10R10UI;
-		case GL_SRGB8:                return sw::FORMAT_SRGB8_X8;
-		case GL_SRGB8_ALPHA8:         return sw::FORMAT_SRGB8_A8;
-		default: UNREACHABLE(format); return sw::FORMAT_NULL;
-		}
-	}
 }
 
 namespace sw2es
diff --git a/src/OpenGL/libGLESv2/utilities.h b/src/OpenGL/libGLESv2/utilities.h
index d773d77..d8e55aa 100644
--- a/src/OpenGL/libGLESv2/utilities.h
+++ b/src/OpenGL/libGLESv2/utilities.h
@@ -42,8 +42,8 @@
 
 	int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
 
-	bool IsCompressed(GLenum format, GLint clientVersion);
-	GLint GetSizedInternalFormat(GLint internalFormat, GLenum type);
+	bool IsCompressed(GLint intenalformat, GLint clientVersion);
+	bool IsSizedInternalFormat(GLint internalformat);   // Not compressed.
 	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
 	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture, GLint clientVersion);
 	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
@@ -55,9 +55,8 @@
 	bool IsCubemapTextureTarget(GLenum target);
 	int CubeFaceIndex(GLenum cubeTarget);
 	bool IsTextureTarget(GLenum target);
-	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLint clientVersion);
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target, GLint clientVersion);
 	GLsizei GetTypeSize(GLenum type);
-	GLenum GetBaseInternalFormat(GLint internalformat);
 
 	bool IsColorRenderable(GLint internalformat, GLint clientVersion);
 	bool IsDepthRenderable(GLint internalformat, GLint clientVersion);
@@ -102,7 +101,6 @@
 	sw::MipmapType ConvertMipMapFilter(GLenum minFilter);
 	sw::FilterType ConvertTextureFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
 	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  GLenum elementType, sw::DrawType &swPrimitiveType, int &primitiveCount, int &verticesPerPrimitive);
-	sw::Format ConvertRenderbufferFormat(GLenum format);
 }
 
 namespace sw2es
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index ce0c6d5..3cb0fc9 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -465,7 +465,7 @@
 		case FORMAT_X8R8G8B8:
 			if(writeRGBA)
 			{
-				Short4 c0 = RoundShort4(c.zyxw) | Short4(0x0000, 0x0000, 0x0000, 0xFFFFu);
+				Short4 c0 = RoundShort4(c.zyxw) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
 				*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
 			}
 			else
@@ -480,7 +480,7 @@
 		case FORMAT_SRGB8_X8:
 			if(writeRGBA)
 			{
-				Short4 c0 = RoundShort4(c) | Short4(0x0000, 0x0000, 0x0000, 0xFFFFu);
+				Short4 c0 = RoundShort4(c) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
 				*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
 			}
 			else