D3D11: Fix loading of RGB5A1 data from RGBA8.

BUG=angleproject:1407
BUG=chromium:616176

Change-Id: I2b88616b6b72dd9caf07fac8ebba9a065cf2983f
Reviewed-on: https://chromium-review.googlesource.com/350907
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 9909fc8..0a10105 100644
--- a/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
+++ b/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
@@ -291,6 +291,11 @@
         "loadFunction": "LoadToNative<GLubyte,4>",
         "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
         "requiresConversion": "false"
+      },
+      {
+        "loadFunction": "LoadRGBA8ToBGR5A1",
+        "dxgiFormat": "DXGI_FORMAT_B5G5R5A1_UNORM",
+        "requiresConversion": "true"
       }
     ],
     "GL_UNSIGNED_SHORT_5_5_5_1": [
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 aa88f70..dc47b14 100644
--- a/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
@@ -1549,6 +1549,7 @@
                 {
                     static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = {
                         { GL_UNSIGNED_SHORT_5_5_5_1, LoadImageFunctionInfo(LoadRGB5A1ToA1RGB5, true) },
+                        { GL_UNSIGNED_BYTE, LoadImageFunctionInfo(LoadRGBA8ToBGR5A1, true) },
                     };
 
                     return loadFunctionsMap;
diff --git a/src/libANGLE/renderer/d3d/loadimage.cpp b/src/libANGLE/renderer/d3d/loadimage.cpp
index a5c69be..79e2dcf 100644
--- a/src/libANGLE/renderer/d3d/loadimage.cpp
+++ b/src/libANGLE/renderer/d3d/loadimage.cpp
@@ -495,6 +495,37 @@
     }
 }
 
+void LoadRGBA8ToBGR5A1(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 uint32_t *source =
+                OffsetDataPointer<uint32_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++)
+            {
+                uint32_t rgba8 = source[x];
+                auto r5        = static_cast<uint16_t>((rgba8 & 0x000000FF) >> 3);
+                auto g5        = static_cast<uint16_t>((rgba8 & 0x0000FF00) >> 11);
+                auto b5        = static_cast<uint16_t>((rgba8 & 0x00FF0000) >> 19);
+                auto a1        = static_cast<uint16_t>((rgba8 & 0xFF000000) >> 31);
+                dest[x]        = (a1 << 15) | (r5 << 10) | (g5 << 5) | b5;
+            }
+        }
+    }
+}
+
 void LoadRGB5A1ToA1RGB5(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 3cf7d8e..72a4690 100644
--- a/src/libANGLE/renderer/d3d/loadimage.h
+++ b/src/libANGLE/renderer/d3d/loadimage.h
@@ -132,6 +132,16 @@
                       const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
                       uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
 
+void LoadRGBA8ToBGR5A1(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 LoadRGB5A1ToA1RGB5(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 56a92de..51e5028 100644
--- a/src/tests/gl_tests/SixteenBppTextureTest.cpp
+++ b/src/tests/gl_tests/SixteenBppTextureTest.cpp
@@ -324,6 +324,25 @@
     simpleValidationBase(tex.get());
 }
 
+// Test uploading RGBA8 data to RGB5A41 textures.
+TEST_P(SixteenBppTextureTestES3, RGB5A1UploadRGBA8)
+{
+    std::vector<GLColor> fourColors;
+    fourColors.push_back(GLColor::red);
+    fourColors.push_back(GLColor::green);
+    fourColors.push_back(GLColor::blue);
+    fourColors.push_back(GLColor::yellow);
+
+    GLTexture tex;
+    glBindTexture(GL_TEXTURE_2D, tex.get());
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 2, 2, 0, GL_RGBA, 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(),