Support reading of half-float formats.

Bug swiftshader:104

Change-Id: I037fcb69131906b52e0c1919f36fea61b2e1c621
Reviewed-on: https://swiftshader-review.googlesource.com/19628
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 57fa354..7d21c63 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3349,6 +3349,8 @@
 	sw::SliceRectF sliceRect(rect);
 	sw::SliceRect dstSliceRect(dstRect);
 	device->blit(renderTarget, sliceRect, externalSurface, dstSliceRect, false, false, false);
+	externalSurface->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
+	externalSurface->unlockExternal();
 	delete externalSurface;
 
 	renderTarget->release();
diff --git a/src/OpenGL/libGLESv2/Framebuffer.cpp b/src/OpenGL/libGLESv2/Framebuffer.cpp
index f466de4..4a9be7b 100644
--- a/src/OpenGL/libGLESv2/Framebuffer.cpp
+++ b/src/OpenGL/libGLESv2/Framebuffer.cpp
@@ -621,11 +621,11 @@
 		case GL_RG32UI:         return GL_UNSIGNED_INT;
 		case GL_RGB32UI:        return GL_UNSIGNED_INT;
 		case GL_RGBA32UI:       return GL_UNSIGNED_INT;
-		case GL_R16F:           return GL_FLOAT;
-		case GL_RG16F:          return GL_FLOAT;
-		case GL_R11F_G11F_B10F: return GL_FLOAT;
-		case GL_RGB16F:         return GL_FLOAT;
-		case GL_RGBA16F:        return GL_FLOAT;
+		case GL_R16F:           return GL_HALF_FLOAT;
+		case GL_RG16F:          return GL_HALF_FLOAT;
+		case GL_R11F_G11F_B10F: return GL_HALF_FLOAT;
+		case GL_RGB16F:         return GL_HALF_FLOAT;
+		case GL_RGBA16F:        return GL_HALF_FLOAT;
 		case GL_R32F:           return GL_FLOAT;
 		case GL_RG32F:          return GL_FLOAT;
 		case GL_RGB32F:         return GL_FLOAT;
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index c531b26..246b71c 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -714,7 +714,9 @@
 			break;
 		}
 
-		if(format == implementationReadFormat && type == implementationReadType)
+		GLenum coreType = (type == GL_HALF_FLOAT_OES) ? GL_HALF_FLOAT : type;
+
+		if(format == implementationReadFormat && coreType == implementationReadType)
 		{
 			return true;
 		}
diff --git a/tests/unittests/unittests.cpp b/tests/unittests/unittests.cpp
index 037112d..371fce3 100644
--- a/tests/unittests/unittests.cpp
+++ b/tests/unittests/unittests.cpp
@@ -30,6 +30,7 @@
 #endif
 
 #include <string.h>
+#include <cstdint>
 
 #define EXPECT_GLENUM_EQ(expected, actual) EXPECT_EQ(static_cast<GLenum>(expected), static_cast<GLenum>(actual))
 
@@ -587,6 +588,44 @@
 	Uninitialize();
 }
 
+// Tests reading of half-float textures.
+TEST_F(SwiftShaderTest, ReadHalfFloat)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_2D, tex);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 256, 256, 0, GL_RGB, GL_HALF_FLOAT, nullptr);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	GLuint fbo = 1;
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+	const float clear_color[4] = { 1.0f, 32.0f, 0.5f, 1.0f };
+	glClearColor(clear_color[0], clear_color[1], clear_color[2], 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	int16_t pixel[3] = { 0x1234, 0x3F80, 0xAAAA };
+	GLint x = 6;
+	GLint y = 3;
+	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 1, 1, GL_RGB, GL_HALF_FLOAT, pixel);
+
+	// This relies on GL_HALF_FLOAT being a valid type for read-back,
+	// which isn't guaranteed by the spec but is supported by SwiftShader.
+	int16_t read_color[3] = { 0, 0, 0 };
+	glReadPixels(x, y, 1, 1, GL_RGB, GL_HALF_FLOAT, &read_color);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	EXPECT_EQ(read_color[0], pixel[0]);
+	EXPECT_EQ(read_color[1], pixel[1]);
+	EXPECT_EQ(read_color[2], pixel[2]);
+
+	Uninitialize();
+}
+
 // Tests construction of a structure containing a single matrix
 TEST_F(SwiftShaderTest, MatrixInStruct)
 {