D3D11: Fix loading of RGBA8 data to RGB565.

BUG=angleproject:1407
BUG=chromium:616176

Change-Id: I663d265abfabb88a5aca8ca0002d2cbc29f6b069
Reviewed-on: https://chromium-review.googlesource.com/350906
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json b/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
index c4483b3..9909fc8 100644
--- a/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
+++ b/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
@@ -943,6 +943,11 @@
         "loadFunction": "LoadToNative3To4<GLubyte,0xFF>",
         "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
         "requiresConversion": "true"
+      },
+      {
+        "loadFunction": "LoadRGB8ToBGR565",
+        "dxgiFormat": "DXGI_FORMAT_B5G6R5_UNORM",
+        "requiresConversion": "true"
       }
     ],
     "GL_UNSIGNED_SHORT_5_6_5": [
diff --git a/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp b/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
index 6ed4825..aa88f70 100644
--- a/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
@@ -1522,6 +1522,7 @@
                 case DXGI_FORMAT_B5G6R5_UNORM:
                 {
                     static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = {
+                        { GL_UNSIGNED_BYTE, LoadImageFunctionInfo(LoadRGB8ToBGR565, true) },
                         { GL_UNSIGNED_SHORT_5_6_5, LoadImageFunctionInfo(LoadToNative<GLushort,1>, false) },
                     };
 
diff --git a/src/libANGLE/renderer/d3d/loadimage.cpp b/src/libANGLE/renderer/d3d/loadimage.cpp
index 40f5042..a5c69be 100644
--- a/src/libANGLE/renderer/d3d/loadimage.cpp
+++ b/src/libANGLE/renderer/d3d/loadimage.cpp
@@ -222,6 +222,38 @@
     }
 }
 
+void LoadRGB8ToBGR565(size_t width,
+                      size_t height,
+                      size_t depth,
+                      const uint8_t *input,
+                      size_t inputRowPitch,
+                      size_t inputDepthPitch,
+                      uint8_t *output,
+                      size_t outputRowPitch,
+                      size_t outputDepthPitch)
+{
+    for (size_t z = 0; z < depth; z++)
+    {
+        for (size_t y = 0; y < height; y++)
+        {
+            const uint8_t *source =
+                OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch);
+            uint16_t *dest =
+                OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
+            for (size_t x = 0; x < width; x++)
+            {
+                uint8_t r8 = source[x * 3 + 0];
+                uint8_t g8 = source[x * 3 + 1];
+                uint8_t b8 = source[x * 3 + 2];
+                auto r5    = static_cast<uint16_t>(r8 >> 3);
+                auto g6    = static_cast<uint16_t>(g8 >> 2);
+                auto b5    = static_cast<uint16_t>(b8 >> 3);
+                dest[x]    = (r5 << 11) | (g6 << 5) | b5;
+            }
+        }
+    }
+}
+
 void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth,
                      const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
                      uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
diff --git a/src/libANGLE/renderer/d3d/loadimage.h b/src/libANGLE/renderer/d3d/loadimage.h
index 4426225..3cf7d8e 100644
--- a/src/libANGLE/renderer/d3d/loadimage.h
+++ b/src/libANGLE/renderer/d3d/loadimage.h
@@ -80,6 +80,16 @@
                    const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
                    uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
 
+void LoadRGB8ToBGR565(size_t width,
+                      size_t height,
+                      size_t depth,
+                      const uint8_t *input,
+                      size_t inputRowPitch,
+                      size_t inputDepthPitch,
+                      uint8_t *output,
+                      size_t outputRowPitch,
+                      size_t outputDepthPitch);
+
 void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth,
                        const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
                        uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
diff --git a/src/tests/gl_tests/SixteenBppTextureTest.cpp b/src/tests/gl_tests/SixteenBppTextureTest.cpp
index eda6039..56a92de 100644
--- a/src/tests/gl_tests/SixteenBppTextureTest.cpp
+++ b/src/tests/gl_tests/SixteenBppTextureTest.cpp
@@ -303,6 +303,27 @@
     simpleValidationBase(tex.get());
 }
 
+// Test uploading RGB8 data to RGB565 textures.
+TEST_P(SixteenBppTextureTestES3, RGB565UploadRGB8)
+{
+    std::vector<GLColorRGB> fourColors;
+    fourColors.push_back(GLColorRGB::red);
+    fourColors.push_back(GLColorRGB::green);
+    fourColors.push_back(GLColorRGB::blue);
+    fourColors.push_back(GLColorRGB::yellow);
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    GLTexture tex;
+    glBindTexture(GL_TEXTURE_2D, tex.get());
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, fourColors.data());
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    ASSERT_GL_NO_ERROR();
+
+    simpleValidationBase(tex.get());
+}
+
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
 ANGLE_INSTANTIATE_TEST(SixteenBppTextureTest,
                        ES2_D3D9(),
diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp
index a9032a1..d30fc70 100644
--- a/src/tests/test_utils/ANGLETest.cpp
+++ b/src/tests/test_utils/ANGLETest.cpp
@@ -15,6 +15,11 @@
 namespace angle
 {
 
+const GLColorRGB GLColorRGB::blue(0u, 0u, 255u);
+const GLColorRGB GLColorRGB::green(0u, 255u, 0u);
+const GLColorRGB GLColorRGB::red(255u, 0u, 0u);
+const GLColorRGB GLColorRGB::yellow(255u, 255u, 0);
+
 const GLColor GLColor::black = GLColor(0u, 0u, 0u, 255u);
 const GLColor GLColor::blue   = GLColor(0u, 0u, 255u, 255u);
 const GLColor GLColor::cyan   = GLColor(0u, 255u, 255u, 255u);
@@ -86,6 +91,14 @@
 TestPlatform g_testPlatformInstance;
 }  // anonymous namespace
 
+GLColorRGB::GLColorRGB() : R(0), G(0), B(0)
+{
+}
+
+GLColorRGB::GLColorRGB(GLubyte r, GLubyte g, GLubyte b) : R(r), G(g), B(b)
+{
+}
+
 GLColor::GLColor() : R(0), G(0), B(0), A(0)
 {
 }
diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h
index a14bd0a..a590f9f 100644
--- a/src/tests/test_utils/ANGLETest.h
+++ b/src/tests/test_utils/ANGLETest.h
@@ -44,6 +44,19 @@
 
 namespace angle
 {
+struct GLColorRGB
+{
+    GLColorRGB();
+    GLColorRGB(GLubyte r, GLubyte g, GLubyte b);
+
+    GLubyte R, G, B;
+
+    static const GLColorRGB blue;
+    static const GLColorRGB green;
+    static const GLColorRGB red;
+    static const GLColorRGB yellow;
+};
+
 struct GLColor
 {
     GLColor();