Fix internal format handling for OpenGL ES 1.1.

With the egl::Image class now only storing the sized internal format,
some OpenGL ES 1.1 functionality broke because it was still expecting a
base format.

Change-Id: Ib41e91f371a06b2a09471ea45dd1f8f56b94091f
Reviewed-on: https://swiftshader-review.googlesource.com/17468
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/OpenGL/libGLES_CM/Context.cpp b/src/OpenGL/libGLES_CM/Context.cpp
index 91f865c..99abd4e 100644
--- a/src/OpenGL/libGLES_CM/Context.cpp
+++ b/src/OpenGL/libGLES_CM/Context.cpp
@@ -2444,12 +2444,12 @@
 		unsigned short *dest16 = (unsigned short*)dest;
 		unsigned int *dest32 = (unsigned int*)dest;
 
-		if(renderTarget->getInternalFormat() == sw::FORMAT_A8B8G8R8 &&
+		if(renderTarget->getExternalFormat() == sw::FORMAT_A8B8G8R8 &&
 		   format == GL_RGBA && type == GL_UNSIGNED_BYTE)
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 4);
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_A8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_A8R8G8B8 &&
 				format == GL_RGBA && type == GL_UNSIGNED_BYTE)
 		{
 			for(int i = 0; i < rect.x1 - rect.x0; i++)
@@ -2459,7 +2459,7 @@
 				dest32[i] = (argb & 0xFF00FF00) | ((argb & 0x000000FF) << 16) | ((argb & 0x00FF0000) >> 16);
 			}
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_X8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_X8R8G8B8 &&
 				format == GL_RGBA && type == GL_UNSIGNED_BYTE)
 		{
 			for(int i = 0; i < rect.x1 - rect.x0; i++)
@@ -2469,7 +2469,7 @@
 				dest32[i] = (xrgb & 0xFF00FF00) | ((xrgb & 0x000000FF) << 16) | ((xrgb & 0x00FF0000) >> 16) | 0xFF000000;
 			}
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_X8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_X8R8G8B8 &&
 				format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)
 		{
 			for(int i = 0; i < rect.x1 - rect.x0; i++)
@@ -2479,17 +2479,17 @@
 				dest32[i] = xrgb | 0xFF000000;
 			}
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_A8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_A8R8G8B8 &&
 				format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 4);
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_A1R5G5B5 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_A1R5G5B5 &&
 				format == GL_BGRA_EXT && type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 2);
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_R5G6B5 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_R5G6B5 &&
 				format == 0x80E0 && type == GL_UNSIGNED_SHORT_5_6_5)   // GL_BGR_EXT
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 2);
@@ -2503,7 +2503,7 @@
 				float b;
 				float a;
 
-				switch(renderTarget->getInternalFormat())
+				switch(renderTarget->getExternalFormat())
 				{
 				case sw::FORMAT_R5G6B5:
 					{
@@ -2577,7 +2577,7 @@
 					break;
 				default:
 					UNIMPLEMENTED();   // FIXME
-					UNREACHABLE(renderTarget->getInternalFormat());
+					UNREACHABLE(renderTarget->getExternalFormat());
 				}
 
 				switch(format)
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.cpp b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
index a0d64cc..c832443 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
@@ -122,7 +122,7 @@
 	return mTexture2D->getHeight(GL_TEXTURE_2D, 0);
 }
 
-GLenum RenderbufferTexture2D::getFormat() const
+GLint RenderbufferTexture2D::getFormat() const
 {
 	return mTexture2D->getFormat(GL_TEXTURE_2D, 0);
 }
@@ -260,7 +260,7 @@
 	return mHeight;
 }
 
-GLenum RenderbufferStorage::getFormat() const
+GLint RenderbufferStorage::getFormat() const
 {
 	return format;
 }
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.h b/src/OpenGL/libGLES_CM/Renderbuffer.h
index f5275f9..4405b93 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.h
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.h
@@ -48,7 +48,7 @@
 
 	virtual GLsizei getWidth() const = 0;
 	virtual GLsizei getHeight() const = 0;
-	virtual GLenum getFormat() const = 0;
+	virtual GLint getFormat() const = 0;
 	virtual GLsizei getSamples() const = 0;
 
 	GLuint getRedSize() const;
@@ -75,7 +75,7 @@
 
 	virtual GLsizei getWidth() const;
 	virtual GLsizei getHeight() const;
-	virtual GLenum getFormat() const;
+	virtual GLint getFormat() const;
 	virtual GLsizei getSamples() const;
 
 private:
@@ -98,7 +98,7 @@
 
 	virtual GLsizei getWidth() const;
 	virtual GLsizei getHeight() const;
-	virtual GLenum getFormat() const;
+	virtual GLint getFormat() const;
 	virtual GLsizei getSamples() const;
 
 protected:
diff --git a/src/OpenGL/libGLES_CM/Texture.cpp b/src/OpenGL/libGLES_CM/Texture.cpp
index d66c723..05f1ebd 100644
--- a/src/OpenGL/libGLES_CM/Texture.cpp
+++ b/src/OpenGL/libGLES_CM/Texture.cpp
@@ -252,21 +252,6 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
-	{
-		return error(GL_INVALID_VALUE);
-	}
-
-	if(IsCompressed(image->getFormat()))
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
-	if(format != image->getFormat())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
 	if(pixels)
 	{
 		gl::PixelStorageModes unpackParameters;
@@ -282,16 +267,6 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
-	{
-		return error(GL_INVALID_VALUE);
-	}
-
-	if(format != image->getFormat())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
 	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);
@@ -432,12 +407,6 @@
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
-{
-	ASSERT(target == GL_TEXTURE_2D);
-	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
-}
-
 int Texture2D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
@@ -782,7 +751,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);
 }
 
 egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
@@ -818,7 +789,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/libGLES_CM/Texture.h b/src/OpenGL/libGLES_CM/Texture.h
index d823c61..0439039 100644
--- a/src/OpenGL/libGLES_CM/Texture.h
+++ b/src/OpenGL/libGLES_CM/Texture.h
@@ -77,7 +77,6 @@
 	virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
 	virtual GLsizei getHeight(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;
 
 	virtual bool isSamplerComplete() const = 0;
@@ -134,7 +133,6 @@
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(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(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.cpp b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
index 440f6cf..f27271c 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.cpp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
@@ -48,41 +48,6 @@
 	return true;
 }
 
-static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, es1::Texture *texture)
-{
-	if(!texture)
-	{
-		return error(GL_INVALID_OPERATION, false);
-	}
-
-	if(compressed != texture->isCompressed(target, level))
-	{
-		return error(GL_INVALID_OPERATION, false);
-	}
-
-	if(format != GL_NONE_OES && format != texture->getFormat(target, level))
-	{
-		return error(GL_INVALID_OPERATION, false);
-	}
-
-	if(compressed)
-	{
-		if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
-		   (height % 4 != 0 && height != texture->getHeight(target, 0)))
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-	}
-
-	if(xoffset + width > texture->getWidth(target, level) ||
-	   yoffset + height > texture->getHeight(target, level))
-	{
-		return error(GL_INVALID_VALUE, false);
-	}
-
-	return true;
-}
-
 void ActiveTexture(GLenum texture)
 {
 	TRACE("(GLenum texture = 0x%X)", texture);
@@ -725,7 +690,6 @@
 	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
 		break;
 	case GL_DEPTH_COMPONENT16_OES:
-	case GL_DEPTH_COMPONENT32_OES:
 	case GL_DEPTH_STENCIL_OES:
 	case GL_DEPTH24_STENCIL8_OES:
 		return error(GL_INVALID_OPERATION);
@@ -832,10 +796,13 @@
 		{
 			es1::Texture2D *texture = context->getTexture2D();
 
-			if(validateSubImageParams(true, width, height, xoffset, yoffset, target, level, format, texture))
+			GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE_OES, texture);
+			if(validationError != GL_NO_ERROR)
 			{
-				texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
+				return error(validationError);
 			}
+
+			texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
 		}
 		else UNREACHABLE(target);
 	}
@@ -1025,9 +992,10 @@
 		}
 		else UNREACHABLE(target);
 
-		if(!validateSubImageParams(false, width, height, xoffset, yoffset, target, level, GL_NONE_OES, texture))
+		GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, width, height, GL_NONE_OES, GL_NONE_OES, texture);
+		if(validationError != GL_NO_ERROR)
 		{
-			return;
+			return error(validationError);
 		}
 
 		texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);
@@ -2292,7 +2260,6 @@
 			"GL_OES_blend_func_separate "
 			"GL_OES_blend_subtract "
 			"GL_OES_compressed_ETC1_RGB8_texture "
-			"GL_OES_depth_texture "
 			"GL_OES_EGL_image "
 			"GL_OES_EGL_image_external "
 			"GL_OES_EGL_sync "
@@ -4231,7 +4198,6 @@
 		switch(type)
 		{
 		case GL_UNSIGNED_BYTE:
-		case GL_FLOAT:
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4242,7 +4208,6 @@
 		{
 		case GL_UNSIGNED_BYTE:
 		case GL_UNSIGNED_SHORT_5_6_5:
-		case GL_FLOAT:
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4254,7 +4219,6 @@
 		case GL_UNSIGNED_BYTE:
 		case GL_UNSIGNED_SHORT_4_4_4_4:
 		case GL_UNSIGNED_SHORT_5_5_5_1:
-		case GL_FLOAT:
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4536,11 +4500,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(!es1::CheckTextureFormatType(format, type))
-	{
-		return error(GL_INVALID_ENUM);
-	}
-
 	if(width == 0 || height == 0 || !pixels)
 	{
 		return;
@@ -4554,10 +4513,13 @@
 		{
 			es1::Texture2D *texture = context->getTexture2D();
 
-			if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, texture))
+			GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture);
+			if(validationError != GL_NO_ERROR)
 			{
-				texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+				return error(validationError);
 			}
+
+			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 b2ba5eb..0df34c7 100644
--- a/src/OpenGL/libGLES_CM/utilities.cpp
+++ b/src/OpenGL/libGLES_CM/utilities.cpp
@@ -32,6 +32,72 @@
                format == GL_ETC1_RGB8_OES;
 	}
 
+	bool IsSizedInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
+		case GL_RGBA8_OES:
+		case GL_BGRA8_EXT:   // GL_APPLE_texture_format_BGRA8888
+		case GL_DEPTH_COMPONENT16_OES:
+		case GL_STENCIL_INDEX8_OES:
+		case GL_DEPTH24_STENCIL8_OES:
+			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)
+	{
+		if(!texture)
+		{
+			return GL_INVALID_OPERATION;
+		}
+
+		GLenum sizedInternalFormat = texture->getFormat(target, level);
+
+		if(compressed)
+		{
+			if(format != sizedInternalFormat)
+			{
+				return GL_INVALID_OPERATION;
+			}
+		}
+		else if(!copy)   // CopyTexSubImage doesn't have format/type parameters.
+		{
+			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target);
+			if(validationError != GL_NO_ERROR)
+			{
+				return validationError;
+			}
+		}
+
+		if(compressed)
+		{
+			if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
+			   (height % 4 != 0 && height != texture->getHeight(target, 0)))
+			{
+				return GL_INVALID_OPERATION;
+			}
+		}
+
+		if(xoffset + width > texture->getWidth(target, level) ||
+		   yoffset + height > texture->getHeight(target, level))
+		{
+			return GL_INVALID_VALUE;
+		}
+
+		return GL_NO_ERROR;
+	}
+
 	bool IsDepthTexture(GLenum format)
 	{
 		return format == GL_DEPTH_STENCIL_OES;
@@ -68,42 +134,195 @@
 	}
 
 	// Verify that format/type are one of the combinations from table 3.4.
-	bool CheckTextureFormatType(GLenum format, GLenum type)
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target)
 	{
 		switch(type)
 		{
 		case GL_UNSIGNED_BYTE:
+		case GL_UNSIGNED_SHORT_4_4_4_4:
+		case GL_UNSIGNED_SHORT_5_5_5_1:
+		case GL_UNSIGNED_SHORT_5_6_5:
+		case GL_UNSIGNED_INT_24_8_OES:   // GL_OES_packed_depth_stencil
+			break;
+		default:
+			return GL_INVALID_ENUM;
+		}
+
+		switch(format)
+		{
+		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
+			break;
+		case GL_DEPTH_STENCIL_OES:   // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
+			switch(target)
+			{
+			case GL_TEXTURE_2D:
+				break;
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		default:
+			return GL_INVALID_ENUM;
+		}
+
+		if((GLenum)internalformat != format)
+		{
+			if(gl::IsUnsizedInternalFormat(internalformat))
+			{
+				return GL_INVALID_OPERATION;
+			}
+
+			if(!IsSizedInternalFormat(internalformat))
+			{
+				return GL_INVALID_VALUE;
+			}
+		}
+
+		if((GLenum)internalformat == format)
+		{
+			// Validate format, type, and unsized internalformat combinations [OpenGL ES 1.1 Table 3.3]
 			switch(format)
 			{
 			case GL_RGBA:
-			case GL_BGRA_EXT:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_UNSIGNED_SHORT_4_4_4_4:
+				case GL_UNSIGNED_SHORT_5_5_5_1:
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
 			case GL_RGB:
-			case GL_ALPHA:
-			case GL_LUMINANCE:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_UNSIGNED_SHORT_5_6_5:
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
 			case GL_LUMINANCE_ALPHA:
-				return true;
+			case GL_LUMINANCE:
+			case GL_ALPHA:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_DEPTH_STENCIL_OES:
+				switch(type)
+				{
+				case GL_UNSIGNED_INT_24_8_OES:   // GL_OES_packed_depth_stencil
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_BGRA_EXT:
+				if(type != GL_UNSIGNED_BYTE)   // GL_APPLE_texture_format_BGRA8888 / GL_EXT_texture_format_BGRA8888
+				{
+					return GL_INVALID_OPERATION;
+				}
+				break;
 			default:
-				return false;
+				UNREACHABLE(format);
+				return GL_INVALID_ENUM;
 			}
-		case GL_FLOAT:
-		case GL_UNSIGNED_SHORT_4_4_4_4:
-		case GL_UNSIGNED_SHORT_5_5_5_1:
-			return (format == GL_RGBA);
-		case GL_UNSIGNED_SHORT_5_6_5:
-			return (format == GL_RGB);
-		case GL_UNSIGNED_INT_24_8_OES:
-			return (format == GL_DEPTH_STENCIL_OES);
-		default:
-			return false;
-		}
-	}
 
-	bool IsColorRenderable(GLenum internalformat)
-	{
-		switch(internalformat)
+			return GL_NO_ERROR;
+		}
+
+		// Validate format, type, and sized internalformat combinations [OpenGL ES 3.0 Table 3.2]
+		bool validSizedInternalformat = false;
+		#define VALIDATE_INTERNALFORMAT(...) { GLint validInternalformats[] = {__VA_ARGS__}; for(GLint v : validInternalformats) {if(internalformat == v) validSizedInternalformat = true;} } break;
+
+		switch(format)
 		{
-		case GL_RGB:
 		case GL_RGBA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:               VALIDATE_INTERNALFORMAT(GL_RGBA8_OES, GL_RGB5_A1_OES, GL_RGBA4_OES)
+			case GL_UNSIGNED_SHORT_4_4_4_4:      VALIDATE_INTERNALFORMAT(GL_RGBA4_OES)
+			case GL_UNSIGNED_SHORT_5_5_5_1:      VALIDATE_INTERNALFORMAT(GL_RGB5_A1_OES)
+			default:                             return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_RGB:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:                VALIDATE_INTERNALFORMAT(GL_RGB8_OES, GL_RGB565_OES)
+			case GL_UNSIGNED_SHORT_5_6_5:         VALIDATE_INTERNALFORMAT(GL_RGB565_OES)
+			default:                              return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_DEPTH_STENCIL_OES:
+			switch(type)
+			{
+			case GL_UNSIGNED_INT_24_8_OES: VALIDATE_INTERNALFORMAT(GL_DEPTH24_STENCIL8_OES)
+			default:                       return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_ALPHA8_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_ALPHA8_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_BGRA_EXT:   // GL_APPLE_texture_format_BGRA8888
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_BGRA8_EXT)
+			default:               return GL_INVALID_OPERATION;
+			}
+			break;
+		default:
+			UNREACHABLE(format);
+			return GL_INVALID_ENUM;
+		}
+
+		#undef VALIDATE_INTERNALFORMAT
+
+		if(!validSizedInternalformat)
+		{
+			return GL_INVALID_OPERATION;
+		}
+
+		return GL_NO_ERROR;
+	}
+
+	bool IsColorRenderable(GLint internalformat)
+	{
+		switch(internalformat)
+		{
 		case GL_RGBA4_OES:
 		case GL_RGB5_A1_OES:
 		case GL_RGB565_OES:
@@ -121,7 +340,7 @@
 		return false;
 	}
 
-	bool IsDepthRenderable(GLenum internalformat)
+	bool IsDepthRenderable(GLint internalformat)
 	{
 		switch(internalformat)
 		{
@@ -142,7 +361,7 @@
 		return false;
 	}
 
-	bool IsStencilRenderable(GLenum internalformat)
+	bool IsStencilRenderable(GLint internalformat)
 	{
 		switch(internalformat)
 		{
@@ -167,45 +386,13 @@
 	{
 		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;
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 1;
+		case GL_RGB565_OES:  return 0;
+		case GL_RGB8_OES:    return 0;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
 		default:
 		//	UNREACHABLE(internalformat);
 			return 0;
@@ -216,45 +403,13 @@
 	{
 		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;
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 5;
+		case GL_RGB565_OES:  return 5;
+		case GL_RGB8_OES:    return 8;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
 		default:
 		//	UNREACHABLE(internalformat);
 			return 0;
@@ -265,45 +420,13 @@
 	{
 		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;
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 5;
+		case GL_RGB565_OES:  return 6;
+		case GL_RGB8_OES:    return 8;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
 		default:
 		//	UNREACHABLE(internalformat);
 			return 0;
@@ -314,45 +437,13 @@
 	{
 		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;
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 5;
+		case GL_RGB565_OES:  return 5;
+		case GL_RGB8_OES:    return 8;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
 		default:
 		//	UNREACHABLE(internalformat);
 			return 0;
@@ -363,13 +454,9 @@
 	{
 		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;
+		case GL_STENCIL_INDEX8_OES:    return 0;
+		case GL_DEPTH_COMPONENT16_OES: return 16;
+		case GL_DEPTH24_STENCIL8_OES:  return 24;
 		default:
 		//	UNREACHABLE(internalformat);
 			return 0;
@@ -380,38 +467,33 @@
 	{
 		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;
+		case GL_STENCIL_INDEX8_OES:    return 8;
+		case GL_DEPTH_COMPONENT16_OES: return 0;
+		case GL_DEPTH24_STENCIL8_OES:  return 8;
 		default:
 		//	UNREACHABLE(internalformat);
 			return 0;
 		}
 	}
 
-	bool IsAlpha(GLenum texFormat)
+	bool IsAlpha(GLint internalformat)
 	{
-		switch(texFormat)
+		switch(internalformat)
 		{
-		case GL_ALPHA:
+		case GL_ALPHA8_EXT:
 			return true;
 		default:
 			return false;
 		}
 	}
 
-	bool IsRGB(GLenum texFormat)
+	bool IsRGB(GLint internalformat)
 	{
-		switch(texFormat)
+		switch(internalformat)
 		{
-		case GL_LUMINANCE:
-		case GL_RGB:
-		case GL_RGB565_OES:   // GL_OES_framebuffer_object
-		case GL_RGB8_OES:     // GL_OES_rgb8_rgba8
+		case GL_LUMINANCE8_EXT:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
 		case SW_YV12_BT601:
 		case SW_YV12_BT709:
 		case SW_YV12_JFIF:
@@ -421,16 +503,16 @@
 		}
 	}
 
-	bool IsRGBA(GLenum texFormat)
+	bool IsRGBA(GLint internalformat)
 	{
-		switch(texFormat)
+		switch(internalformat)
 		{
-		case GL_LUMINANCE_ALPHA:
+		case GL_LUMINANCE8_ALPHA8_EXT:
 		case GL_RGBA:
-		case GL_BGRA_EXT:      // GL_EXT_texture_format_BGRA8888
-		case GL_RGBA4_OES:     // GL_OES_framebuffer_object
-		case GL_RGB5_A1_OES:   // GL_OES_framebuffer_object
-		case GL_RGBA8_OES:     // GL_OES_rgb8_rgba8
+		case GL_BGRA8_EXT:     // GL_EXT_texture_format_BGRA8888
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGBA8_OES:
 			return true;
 		default:
 			return false;
@@ -708,7 +790,7 @@
 		sw::DrawType elementSize;
 		switch(elementType)
 		{
-		case GL_NONE:           elementSize = sw::DRAW_NONINDEXED; break;
+		case GL_NONE_OES:       elementSize = sw::DRAW_NONINDEXED; break;
 		case GL_UNSIGNED_BYTE:  elementSize = sw::DRAW_INDEXED8;   break;
 		case GL_UNSIGNED_SHORT: elementSize = sw::DRAW_INDEXED16;  break;
 		case GL_UNSIGNED_INT:   elementSize = sw::DRAW_INDEXED32;  break;
@@ -720,22 +802,6 @@
 		return true;
 	}
 
-	sw::Format ConvertRenderbufferFormat(GLenum format)
-	{
-		switch(format)
-		{
-		case GL_RGBA4_OES:
-		case GL_RGB5_A1_OES:
-		case GL_RGBA8_OES:            return sw::FORMAT_A8B8G8R8;
-		case GL_RGB565_OES:           return sw::FORMAT_R5G6B5;
-		case GL_RGB8_OES:             return sw::FORMAT_X8B8G8R8;
-		case GL_DEPTH_COMPONENT16_OES:
-		case GL_STENCIL_INDEX8_OES:
-		case GL_DEPTH24_STENCIL8_OES: return sw::FORMAT_D24S8;
-		default: UNREACHABLE(format); return sw::FORMAT_A8B8G8R8;
-		}
-	}
-
 	sw::TextureStage::StageOperation ConvertCombineOperation(GLenum operation)
 	{
 		switch(operation)
diff --git a/src/OpenGL/libGLES_CM/utilities.h b/src/OpenGL/libGLES_CM/utilities.h
index 4f55c86..402a341 100644
--- a/src/OpenGL/libGLES_CM/utilities.h
+++ b/src/OpenGL/libGLES_CM/utilities.h
@@ -31,16 +31,18 @@
 	struct Color;
 
 	bool IsCompressed(GLenum format);
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture);
 	bool IsDepthTexture(GLenum format);
 	bool IsStencilTexture(GLenum format);
 	bool IsCubemapTextureTarget(GLenum target);
 	int CubeFaceIndex(GLenum cubeTarget);
 	bool IsTextureTarget(GLenum target);
-	bool CheckTextureFormatType(GLenum format, GLenum type);
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target);
 
-	bool IsColorRenderable(GLenum internalformat);
-	bool IsDepthRenderable(GLenum internalformat);
-	bool IsStencilRenderable(GLenum internalformat);
+	bool IsColorRenderable(GLint internalformat);
+	bool IsDepthRenderable(GLint internalformat);
+	bool IsStencilRenderable(GLint internalformat);
 
 	GLuint GetAlphaSize(GLint internalformat);
 	GLuint GetRedSize(GLint internalformat);
@@ -49,9 +51,9 @@
 	GLuint GetDepthSize(GLint internalformat);
 	GLuint GetStencilSize(GLint internalformat);
 
-	bool IsAlpha(GLenum texFormat);
-	bool IsRGB(GLenum texFormat);
-	bool IsRGBA(GLenum texFormat);
+	bool IsAlpha(GLint texFormat);
+	bool IsRGB(GLint texFormat);
+	bool IsRGBA(GLint texFormat);
 }
 
 namespace es2sw
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index 3d01ee5..1e3e51f 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -509,7 +509,7 @@
 	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 == getTarget());
 	return image[level] ? image[level]->getFormat() : GL_NONE;
@@ -966,7 +966,7 @@
 	return image[face][level] ? image[face][level]->getHeight() : 0;
 }
 
-GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
+GLint TextureCubeMap::getFormat(GLenum target, GLint level) const
 {
 	int face = CubeFaceIndex(target);
 	return image[face][level] ? image[face][level]->getFormat() : 0;
@@ -1475,7 +1475,7 @@
 	return image[level] ? image[level]->getDepth() : 0;
 }
 
-GLenum Texture3D::getFormat(GLenum target, GLint level) const
+GLint Texture3D::getFormat(GLenum target, GLint level) const
 {
 	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getFormat() : GL_NONE;
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index b33c1bc..13b3a56 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -93,7 +93,7 @@
 	virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
 	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 GLint getFormat(GLenum target, GLint level) const = 0;
 	virtual int getTopLevel() const = 0;
 
 	virtual bool isSamplerComplete() const = 0;
@@ -155,7 +155,7 @@
 
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
+	GLint getFormat(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
 	void setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
@@ -220,7 +220,7 @@
 
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
+	GLint getFormat(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
 	void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
@@ -281,7 +281,7 @@
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
 	GLsizei getDepth(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
+	GLint getFormat(GLenum target, GLint level) const override;
 	int getTopLevel() const override;
 
 	void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);