Fix texture uploads using different formats.

Bug 21716622

Change-Id: I3154fc0c3da5c9f2f280101e8e5840ca45eb144e
Reviewed-on: https://swiftshader-review.googlesource.com/3446
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp
index c1f939a..830be02 100644
--- a/src/OpenGL/common/Image.cpp
+++ b/src/OpenGL/common/Image.cpp
@@ -11,6 +11,7 @@
 
 #include "Image.hpp"
 
+#include "Renderer/Blitter.hpp"
 #include "../libEGL/Texture.hpp"
 #include "../common/debug.h"
 #include "Common/Thread.hpp"
@@ -356,6 +357,77 @@
 
 namespace egl
 {
+	sw::Format ConvertFormatType(GLenum format, GLenum type)
+	{
+		switch(format)
+		{
+		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return sw::FORMAT_L8;
+			case GL_HALF_FLOAT:     return sw::FORMAT_L16F;
+			case GL_HALF_FLOAT_OES: return sw::FORMAT_L16F;
+			case GL_FLOAT:          return sw::FORMAT_L32F;
+			default: UNREACHABLE();
+			}
+			break;
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return sw::FORMAT_A8L8;
+			case GL_HALF_FLOAT:     return sw::FORMAT_A16L16F;
+			case GL_HALF_FLOAT_OES: return sw::FORMAT_A16L16F;
+			case GL_FLOAT:          return sw::FORMAT_A32L32F;
+			default: UNREACHABLE();
+			}
+			break;
+		case GL_RGBA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:          return sw::FORMAT_A8B8G8R8;
+			case GL_UNSIGNED_SHORT_4_4_4_4: return sw::FORMAT_R4G4B4A4;
+			case GL_UNSIGNED_SHORT_5_5_5_1: return sw::FORMAT_R5G5B5A1;
+			case GL_HALF_FLOAT:             return sw::FORMAT_A16B16G16R16F;
+			case GL_HALF_FLOAT_OES:         return sw::FORMAT_A16B16G16R16F;
+			case GL_FLOAT:                  return sw::FORMAT_A32B32G32R32F;
+			default: UNREACHABLE();
+			}
+			break;
+		case GL_BGRA_EXT:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:          return sw::FORMAT_A8R8G8B8;
+			default: UNREACHABLE();
+			}
+			break;
+		case GL_RGB:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:          return sw::FORMAT_B8G8R8;
+			case GL_UNSIGNED_SHORT_5_6_5:   return sw::FORMAT_R5G6B5;
+			case GL_HALF_FLOAT:             return sw::FORMAT_B16G16R16F;
+			case GL_HALF_FLOAT_OES:         return sw::FORMAT_B16G16R16F;
+			case GL_FLOAT:                  return sw::FORMAT_B32G32R32F;
+			default: UNREACHABLE();
+			}
+			break;
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:          return sw::FORMAT_A8;
+			case GL_HALF_FLOAT:             return sw::FORMAT_A16F;
+			case GL_HALF_FLOAT_OES:         return sw::FORMAT_A16F;
+			case GL_FLOAT:                  return sw::FORMAT_A32F;
+			default: UNREACHABLE();
+			}
+			break;
+		default:
+			UNREACHABLE();
+		}
+
+		return sw::FORMAT_NULL;
+	}
+
 	sw::Format SelectInternalFormat(GLenum format, GLenum type)
 	{
 		if(format == GL_ETC1_RGB8_OES)
@@ -588,119 +660,130 @@
 		GLsizei inputPitch  = (unpackInfo.rowLength == 0) ? ComputePitch(width, format, type, unpackInfo.alignment) : unpackInfo.rowLength;
 		GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight;
 		input = ((char*)input) + (unpackInfo.skipImages * inputHeight + unpackInfo.skipRows) * inputPitch + unpackInfo.skipPixels;
-		void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
 
-		if(buffer)
+		if(SelectInternalFormat(format, type) == internalFormat)
 		{
-			switch(type)
-			{
-			case GL_UNSIGNED_BYTE:
-				switch(format)
-				{
-				case GL_ALPHA:
-					LoadImageData<Alpha>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_LUMINANCE:
-					LoadImageData<Luminance>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_LUMINANCE_ALPHA:
-					LoadImageData<LuminanceAlpha>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_RGB:
-					LoadImageData<UByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_RGBA:
-				case GL_BGRA_EXT:
-					LoadImageData<UByte4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				default: UNREACHABLE();
-				}
-				break;
-			case GL_UNSIGNED_SHORT_5_6_5:
-				switch(format)
-				{
-				case GL_RGB:
-					LoadImageData<RGB565>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				default: UNREACHABLE();
-				}
-				break;
-			case GL_UNSIGNED_SHORT_4_4_4_4:
-				switch(format)
-				{
-				case GL_RGBA:
-					LoadImageData<RGBA4444>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				default: UNREACHABLE();
-				}
-				break;
-			case GL_UNSIGNED_SHORT_5_5_5_1:
-				switch(format)
-				{
-				case GL_RGBA:
-					LoadImageData<RGBA5551>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				default: UNREACHABLE();
-				}
-				break;
-			case GL_FLOAT:
-				switch(format)
-				{
-				// float textures are converted to RGBA, not BGRA
-				case GL_ALPHA:
-					LoadImageData<AlphaFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_LUMINANCE:
-					LoadImageData<LuminanceFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_LUMINANCE_ALPHA:
-					LoadImageData<LuminanceAlphaFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_RGB:
-					LoadImageData<FloatRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_RGBA:
-					LoadImageData<Float4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				default: UNREACHABLE();
-				}
-				break;
-			case GL_HALF_FLOAT:
-			case GL_HALF_FLOAT_OES:
-				switch(format)
-				{
-				case GL_ALPHA:
-					LoadImageData<AlphaHalfFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_LUMINANCE:
-					LoadImageData<LuminanceHalfFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_LUMINANCE_ALPHA:
-					LoadImageData<LuminanceAlphaHalfFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_RGB:
-					LoadImageData<HalfFloatRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				case GL_RGBA:
-					LoadImageData<HalfFloat4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-					break;
-				default: UNREACHABLE();
-				}
-				break;
-			case GL_UNSIGNED_SHORT:
-				LoadImageData<D16>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-				break;
-			case GL_UNSIGNED_INT:
-				LoadImageData<D32>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
-				break;
-			case GL_UNSIGNED_INT_24_8_OES:
-				loadD24S8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer);
-				break;
-			default: UNREACHABLE();
-			}
-		}
+			void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
 
-		unlock();
+			if(buffer)
+			{
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+					switch(format)
+					{
+					case GL_ALPHA:
+						LoadImageData<Alpha>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_LUMINANCE:
+						LoadImageData<Luminance>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_LUMINANCE_ALPHA:
+						LoadImageData<LuminanceAlpha>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_RGB:
+						LoadImageData<UByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_RGBA:
+					case GL_BGRA_EXT:
+						LoadImageData<UByte4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					default: UNREACHABLE();
+					}
+					break;
+				case GL_UNSIGNED_SHORT_5_6_5:
+					switch(format)
+					{
+					case GL_RGB:
+						LoadImageData<RGB565>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					default: UNREACHABLE();
+					}
+					break;
+				case GL_UNSIGNED_SHORT_4_4_4_4:
+					switch(format)
+					{
+					case GL_RGBA:
+						LoadImageData<RGBA4444>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					default: UNREACHABLE();
+					}
+					break;
+				case GL_UNSIGNED_SHORT_5_5_5_1:
+					switch(format)
+					{
+					case GL_RGBA:
+						LoadImageData<RGBA5551>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					default: UNREACHABLE();
+					}
+					break;
+				case GL_FLOAT:
+					switch(format)
+					{
+					// float textures are converted to RGBA, not BGRA
+					case GL_ALPHA:
+						LoadImageData<AlphaFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_LUMINANCE:
+						LoadImageData<LuminanceFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_LUMINANCE_ALPHA:
+						LoadImageData<LuminanceAlphaFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_RGB:
+						LoadImageData<FloatRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_RGBA:
+						LoadImageData<Float4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					default: UNREACHABLE();
+					}
+					break;
+				case GL_HALF_FLOAT:
+				case GL_HALF_FLOAT_OES:
+					switch(format)
+					{
+					case GL_ALPHA:
+						LoadImageData<AlphaHalfFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_LUMINANCE:
+						LoadImageData<LuminanceHalfFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_LUMINANCE_ALPHA:
+						LoadImageData<LuminanceAlphaHalfFloat>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_RGB:
+						LoadImageData<HalfFloatRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					case GL_RGBA:
+						LoadImageData<HalfFloat4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+						break;
+					default: UNREACHABLE();
+					}
+					break;
+				case GL_UNSIGNED_SHORT:
+					LoadImageData<D16>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+					break;
+				case GL_UNSIGNED_INT:
+					LoadImageData<D32>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer, internalFormat);
+					break;
+				case GL_UNSIGNED_INT_24_8_OES:
+					loadD24S8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer);
+					break;
+				default: UNREACHABLE();
+				}
+			}
+
+			unlock();
+		}
+		else
+		{
+			sw::Surface source(width, height, depth, ConvertFormatType(format, type), const_cast<void*>(input), inputPitch, inputPitch * inputHeight);
+			sw::Rect sourceRect(0, 0, width, height);
+			sw::Rect destRect(xoffset, yoffset, xoffset + width, yoffset + height);
+			sw::blitter.blit(&source, sourceRect, this, destRect, false);
+		}
 	}
 
 	void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer)