Support BGRA texture by remapping the internal format to RGBA.

The format is still passed as BGRA to the driver so that the data can be
properly unpacked.

BUG=angleproject:884

Change-Id: I767626c818ce1a3c5a4739f07aa623bf8a9ae377
Reviewed-on: https://chromium-review.googlesource.com/273162
Reviewed-by: Brandon Jones <bajones@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/RenderbufferGL.cpp b/src/libANGLE/renderer/gl/RenderbufferGL.cpp
index 358da74..a5877f6 100644
--- a/src/libANGLE/renderer/gl/RenderbufferGL.cpp
+++ b/src/libANGLE/renderer/gl/RenderbufferGL.cpp
@@ -13,6 +13,7 @@
 #include "libANGLE/angletypes.h"
 #include "libANGLE/renderer/gl/FunctionsGL.h"
 #include "libANGLE/renderer/gl/StateManagerGL.h"
+#include "libANGLE/renderer/gl/formatutilsgl.h"
 #include "libANGLE/renderer/gl/renderergl_utils.h"
 
 namespace rx
@@ -38,14 +39,19 @@
 gl::Error RenderbufferGL::setStorage(GLenum internalformat, size_t width, size_t height)
 {
     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
-    mFunctions->renderbufferStorage(GL_RENDERBUFFER, internalformat, width, height);
+
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalformat, mFunctions->standard);
+    mFunctions->renderbufferStorage(GL_RENDERBUFFER, nativeInternalFormatInfo.internalFormat, width, height);
+
     return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error RenderbufferGL::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height)
 {
     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
-    mFunctions->renderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, width, height);
+
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalformat, mFunctions->standard);
+    mFunctions->renderbufferStorageMultisample(GL_RENDERBUFFER, samples, nativeInternalFormatInfo.internalFormat, width, height);
 
     const gl::TextureCaps &formatCaps = mTextureCaps.get(internalformat);
     if (samples > formatCaps.getMaxSamples())
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index 91b3f5e..e113ab6 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -17,6 +17,7 @@
 #include "libANGLE/renderer/gl/FramebufferGL.h"
 #include "libANGLE/renderer/gl/FunctionsGL.h"
 #include "libANGLE/renderer/gl/StateManagerGL.h"
+#include "libANGLE/renderer/gl/formatutilsgl.h"
 
 namespace rx
 {
@@ -92,15 +93,17 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalFormat, mFunctions->standard);
+
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(size.depth == 1);
-        mFunctions->texImage2D(target, level, internalFormat, size.width, size.height, 0, format, type, pixels);
+        mFunctions->texImage2D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, 0, format, type, pixels);
     }
     else if (UseTexImage3D(mTextureType))
     {
-        mFunctions->texImage3D(target, level, internalFormat, size.width, size.height, size.depth, 0, format, type, pixels);
+        mFunctions->texImage3D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, size.depth, 0, format, type, pixels);
     }
     else
     {
@@ -143,15 +146,17 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalFormat, mFunctions->standard);
+
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(size.depth == 1);
-        mFunctions->compressedTexImage2D(target, level, internalFormat, size.width, size.height, 0, imageSize, pixels);
+        mFunctions->compressedTexImage2D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, 0, imageSize, pixels);
     }
     else if (UseTexImage3D(mTextureType))
     {
-        mFunctions->compressedTexImage3D(target, level, internalFormat, size.width, size.height, size.depth, 0,
+        mFunctions->compressedTexImage3D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, size.depth, 0,
                                          imageSize, pixels);
     }
     else
@@ -169,17 +174,19 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(format, mFunctions->standard);
+
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(area.z == 0 && area.depth == 1);
-        mFunctions->compressedTexSubImage2D(target, level, area.x, area.y, area.width, area.height, format, imageSize,
+        mFunctions->compressedTexSubImage2D(target, level, area.x, area.y, area.width, area.height, nativeInternalFormatInfo.internalFormat, imageSize,
                                             pixels);
     }
     else if (UseTexImage3D(mTextureType))
     {
         mFunctions->compressedTexSubImage3D(target, level, area.x, area.y, area.z, area.width, area.height, area.depth,
-                                            format, imageSize, pixels);
+                                            nativeInternalFormatInfo.internalFormat, imageSize, pixels);
     }
     else
     {
@@ -192,6 +199,8 @@
 gl::Error TextureGL::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
                                const gl::Framebuffer *source)
 {
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalFormat, mFunctions->standard);
+
     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
 
     mStateManager->bindTexture(mTextureType, mTextureID);
@@ -199,7 +208,7 @@
 
     if (UseTexImage2D(mTextureType))
     {
-        mFunctions->copyTexImage2D(target, level, internalFormat, sourceArea.x, sourceArea.y,
+        mFunctions->copyTexImage2D(target, level, nativeInternalFormatInfo.internalFormat, sourceArea.x, sourceArea.y,
                                    sourceArea.width, sourceArea.height, 0);
     }
     else
@@ -242,13 +251,15 @@
     // TODO: emulate texture storage with TexImage calls if on GL version <4.2 or the
     // ARB_texture_storage extension is not available.
 
+    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalFormat, mFunctions->standard);
+
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(size.depth == 1);
         if (mFunctions->texStorage2D)
         {
-            mFunctions->texStorage2D(target, levels, internalFormat, size.width, size.height);
+            mFunctions->texStorage2D(target, levels, nativeInternalFormatInfo.internalFormat, size.width, size.height);
         }
         else
         {
@@ -271,12 +282,12 @@
                     if (internalFormatInfo.compressed)
                     {
                         size_t dataSize = internalFormatInfo.computeBlockSize(GL_UNSIGNED_BYTE, levelSize.width, levelSize.height);
-                        mFunctions->compressedTexImage2D(target, level, internalFormat, levelSize.width, levelSize.height,
+                        mFunctions->compressedTexImage2D(target, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
                                                          0, dataSize, nullptr);
                     }
                     else
                     {
-                        mFunctions->texImage2D(target, level, internalFormat, levelSize.width, levelSize.height,
+                        mFunctions->texImage2D(target, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
                                                0, internalFormatInfo.format, internalFormatInfo.type, nullptr);
                     }
                 }
@@ -287,12 +298,12 @@
                         if (internalFormatInfo.compressed)
                         {
                             size_t dataSize = internalFormatInfo.computeBlockSize(GL_UNSIGNED_BYTE, levelSize.width, levelSize.height);
-                            mFunctions->compressedTexImage2D(face, level, internalFormat, levelSize.width, levelSize.height,
+                            mFunctions->compressedTexImage2D(face, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
                                                              0, dataSize, nullptr);
                         }
                         else
                         {
-                            mFunctions->texImage2D(face, level, internalFormat, levelSize.width, levelSize.height,
+                            mFunctions->texImage2D(face, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
                                                     0, internalFormatInfo.format, internalFormatInfo.type, nullptr);
                         }
                     }
@@ -308,7 +319,7 @@
     {
         if (mFunctions->texStorage3D)
         {
-            mFunctions->texStorage3D(target, levels, internalFormat, size.width, size.height, size.depth);
+            mFunctions->texStorage3D(target, levels, nativeInternalFormatInfo.internalFormat, size.width, size.height, size.depth);
         }
         else
         {
@@ -329,12 +340,12 @@
                 if (internalFormatInfo.compressed)
                 {
                     size_t dataSize = internalFormatInfo.computeBlockSize(GL_UNSIGNED_BYTE, levelSize.width, levelSize.height) * levelSize.depth;
-                    mFunctions->compressedTexImage3D(target, i, internalFormat, levelSize.width, levelSize.height, levelSize.depth,
+                    mFunctions->compressedTexImage3D(target, i, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height, levelSize.depth,
                                                      0, dataSize, nullptr);
                 }
                 else
                 {
-                    mFunctions->texImage3D(target, i, internalFormat, levelSize.width, levelSize.height, levelSize.depth,
+                    mFunctions->texImage3D(target, i, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height, levelSize.depth,
                                            0, internalFormatInfo.format, internalFormatInfo.type, nullptr);
                 }
             }
diff --git a/src/libANGLE/renderer/gl/formatutilsgl.cpp b/src/libANGLE/renderer/gl/formatutilsgl.cpp
index 4ef4b3a..6f0fe7f 100644
--- a/src/libANGLE/renderer/gl/formatutilsgl.cpp
+++ b/src/libANGLE/renderer/gl/formatutilsgl.cpp
@@ -9,7 +9,6 @@
 
 #include "libANGLE/renderer/gl/formatutilsgl.h"
 
-#include <map>
 #include <limits>
 
 #include "common/string_utils.h"
@@ -20,6 +19,52 @@
 namespace nativegl
 {
 
+typedef std::map<GLenum, GLenum> InternalFormatConversionMap;
+
+static InternalFormatConversionMap BuildGLInternalFormatConversionMap()
+{
+    InternalFormatConversionMap map;
+
+    map[GL_BGRA8_EXT] = GL_RGBA8;
+    map[GL_BGRA_EXT] = GL_RGBA;
+
+    return map;
+}
+
+static InternalFormatConversionMap BuildGLESInternalFormatConversionMap()
+{
+    InternalFormatConversionMap map;
+
+    return map;
+}
+
+static const InternalFormatConversionMap &GetInternalFormatConversionMap(StandardGL standard)
+{
+    if (standard == STANDARD_GL_DESKTOP)
+    {
+        static const InternalFormatConversionMap map = BuildGLInternalFormatConversionMap();
+        return map;
+    }
+    else if (standard == STANDARD_GL_ES)
+    {
+        static const InternalFormatConversionMap map = BuildGLESInternalFormatConversionMap();
+        return map;
+    }
+    else
+    {
+        UNREACHABLE();
+        static const InternalFormatConversionMap map;
+        return map;
+    }
+}
+
+static GLenum GetConvertedInternalFormat(GLenum format, StandardGL standard)
+{
+    const InternalFormatConversionMap &map = GetInternalFormatConversionMap(standard);
+    auto iter = map.find(format);
+    return iter != map.end() ? iter->second : format;
+}
+
 SupportRequirement::SupportRequirement()
     : version(std::numeric_limits<GLuint>::max(), std::numeric_limits<GLuint>::max()),
       versionExtensions(),
@@ -109,10 +154,12 @@
                                        const SupportRequirement &esTexture, const SupportRequirement &esFilter, const SupportRequirement &esRender)
 {
     InternalFormatInfo formatInfo;
+    formatInfo.glInfo.internalFormat = GetConvertedInternalFormat(internalFormat, STANDARD_GL_DESKTOP);
     formatInfo.glInfo.texture = desktopTexture;
     formatInfo.glInfo.filter = desktopFilter;
     formatInfo.glInfo.renderbuffer = desktopRender;
     formatInfo.glInfo.framebufferAttachment = desktopRender;
+    formatInfo.glesInfo.internalFormat = GetConvertedInternalFormat(internalFormat, STANDARD_GL_ES);
     formatInfo.glesInfo.texture = esTexture;
     formatInfo.glesInfo.filter = esTexture;
     formatInfo.glesInfo.renderbuffer = esFilter;
@@ -181,8 +228,8 @@
     InsertFormatMapping(&map, GL_SRGB_ALPHA,        VersionOrExts(2, 1, "GL_EXT_texture_sRGB"),       Always(), VersionOrExts(2, 1, "GL_EXT_texture_sRGB"),    VersionOrExts(3, 0, "GL_EXT_texture_sRGB"), Always(), VersionOrExts(3, 0, "GL_EXT_texture_sRGB"));
 
     // From GL_EXT_texture_format_BGRA8888
-    InsertFormatMapping(&map, GL_BGRA8_EXT,         Never(),                                          Never(),  Never(),                                       ExtsOnly("GL_EXT_texture_format_BGRA8888"), Always(), ExtsOnly("GL_EXT_texture_format_BGRA8888"));
-    InsertFormatMapping(&map, GL_BGRA_EXT,          Never(),                                          Never(),  Never(),                                       ExtsOnly("GL_EXT_texture_format_BGRA8888"), Always(), ExtsOnly("GL_EXT_texture_format_BGRA8888"));
+    InsertFormatMapping(&map, GL_BGRA8_EXT,         VersionOrExts(1, 2, "GL_EXT_bgra"),               Always(), VersionOrExts(1, 2, "GL_EXT_bgra"),            ExtsOnly("GL_EXT_texture_format_BGRA8888"), Always(), ExtsOnly("GL_EXT_texture_format_BGRA8888"));
+    InsertFormatMapping(&map, GL_BGRA_EXT,          VersionOrExts(1, 2, "GL_EXT_bgra"),               Always(), VersionOrExts(1, 2, "GL_EXT_bgra"),            ExtsOnly("GL_EXT_texture_format_BGRA8888"), Always(), ExtsOnly("GL_EXT_texture_format_BGRA8888"));
 
     // Floating point formats
     //                       | Format              | OpenGL texture support                                       | Filter  | OpenGL render support                                                                            | OpenGL ES texture support                                         | Filter                                                 | OpenGL ES render support                                         |
diff --git a/src/libANGLE/renderer/gl/formatutilsgl.h b/src/libANGLE/renderer/gl/formatutilsgl.h
index dc5ab7f..7c4360f 100644
--- a/src/libANGLE/renderer/gl/formatutilsgl.h
+++ b/src/libANGLE/renderer/gl/formatutilsgl.h
@@ -10,6 +10,7 @@
 #ifndef LIBANGLE_RENDERER_GL_FORMATUTILSGL_H_
 #define LIBANGLE_RENDERER_GL_FORMATUTILSGL_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -41,6 +42,9 @@
 {
     InternalFormat();
 
+    // Internal format to use for the native texture
+    GLenum internalFormat;
+
     SupportRequirement texture;
     SupportRequirement filter;
     SupportRequirement renderbuffer;