Centralize GL format workarounds.

Instead of trying to encapsulate the GL texture format workarounds into
tables, use functions that do manual checks for specific cases.  Simplifies
the logic.

Fixes:
 * conformance/extensions/ext-sRGB.html
 * conformance/extensions/oes-texture-half-float.html
 * conformance/extensions/oes-texture-half-float-with-canvas.html
 * conformance/extensions/oes-texture-half-float-with-image.htm
 * conformance/extensions/oes-texture-half-float-with-video.html

BUG=angleproject:884

Change-Id: Ifb719fff908680fddc7c53a544e2284a42a58356
Reviewed-on: https://chromium-review.googlesource.com/289082
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Geoff Lang <geofflang@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 a5877f6..320c5f4 100644
--- a/src/libANGLE/renderer/gl/RenderbufferGL.cpp
+++ b/src/libANGLE/renderer/gl/RenderbufferGL.cpp
@@ -18,10 +18,13 @@
 
 namespace rx
 {
-
-RenderbufferGL::RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager, const gl::TextureCapsMap &textureCaps)
+RenderbufferGL::RenderbufferGL(const FunctionsGL *functions,
+                               const WorkaroundsGL &workarounds,
+                               StateManagerGL *stateManager,
+                               const gl::TextureCapsMap &textureCaps)
     : RenderbufferImpl(),
       mFunctions(functions),
+      mWorkarounds(workarounds),
       mStateManager(stateManager),
       mTextureCaps(textureCaps),
       mRenderbufferID(0)
@@ -40,8 +43,10 @@
 {
     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
 
-    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalformat, mFunctions->standard);
-    mFunctions->renderbufferStorage(GL_RENDERBUFFER, nativeInternalFormatInfo.internalFormat, width, height);
+    nativegl::RenderbufferFormat renderbufferFormat =
+        nativegl::GetRenderbufferFormat(mFunctions, mWorkarounds, internalformat);
+    mFunctions->renderbufferStorage(GL_RENDERBUFFER, renderbufferFormat.internalFormat, width,
+                                    height);
 
     return gl::Error(GL_NO_ERROR);
 }
@@ -50,8 +55,10 @@
 {
     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
 
-    const nativegl::InternalFormat &nativeInternalFormatInfo = nativegl::GetInternalFormatInfo(internalformat, mFunctions->standard);
-    mFunctions->renderbufferStorageMultisample(GL_RENDERBUFFER, samples, nativeInternalFormatInfo.internalFormat, width, height);
+    nativegl::RenderbufferFormat renderbufferFormat =
+        nativegl::GetRenderbufferFormat(mFunctions, mWorkarounds, internalformat);
+    mFunctions->renderbufferStorageMultisample(GL_RENDERBUFFER, samples,
+                                               renderbufferFormat.internalFormat, width, height);
 
     const gl::TextureCaps &formatCaps = mTextureCaps.get(internalformat);
     if (samples > formatCaps.getMaxSamples())
diff --git a/src/libANGLE/renderer/gl/RenderbufferGL.h b/src/libANGLE/renderer/gl/RenderbufferGL.h
index f26341f..c610155 100644
--- a/src/libANGLE/renderer/gl/RenderbufferGL.h
+++ b/src/libANGLE/renderer/gl/RenderbufferGL.h
@@ -21,11 +21,15 @@
 
 class FunctionsGL;
 class StateManagerGL;
+struct WorkaroundsGL;
 
 class RenderbufferGL : public RenderbufferImpl
 {
   public:
-    RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager, const gl::TextureCapsMap &textureCaps);
+    RenderbufferGL(const FunctionsGL *functions,
+                   const WorkaroundsGL &workarounds,
+                   StateManagerGL *stateManager,
+                   const gl::TextureCapsMap &textureCaps);
     ~RenderbufferGL() override;
 
     virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
@@ -41,6 +45,7 @@
 
   private:
     const FunctionsGL *mFunctions;
+    const WorkaroundsGL &mWorkarounds;
     StateManagerGL *mStateManager;
     const gl::TextureCapsMap &mTextureCaps;
 
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index 30413af..db8ed00 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -198,7 +198,7 @@
 
 RenderbufferImpl *RendererGL::createRenderbuffer()
 {
-    return new RenderbufferGL(mFunctions, mStateManager, getRendererTextureCaps());
+    return new RenderbufferGL(mFunctions, mWorkarounds, mStateManager, getRendererTextureCaps());
 }
 
 BufferImpl *RendererGL::createBuffer()
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index acd4cf1..fa4bf71 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -56,32 +56,6 @@
     }
 }
 
-static const nativegl::InternalFormat &GetNativeInternalFormat(const FunctionsGL *functions,
-                                                               const WorkaroundsGL &workarounds,
-                                                               GLenum internalFormat,
-                                                               GLenum type)
-{
-    GLenum sizedFormat                   = gl::GetSizedInternalFormat(internalFormat, type);
-    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat);
-
-    bool use1BitAlphaWorkaround = workarounds.avoid1BitAlphaTextureFormats &&
-                                  functions->standard == STANDARD_GL_DESKTOP &&
-                                  formatInfo.alphaBits == 1;
-    if (!use1BitAlphaWorkaround &&
-        (functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0))))
-    {
-        // Use sized internal formats whenever possible to guarantee the requested precision.
-        // On Desktop GL, passing an internal format of GL_RGBA will generate a GL_RGBA8 texture
-        // even if the provided type is GL_FLOAT.
-        return nativegl::GetInternalFormatInfo(sizedFormat, functions->standard);
-    }
-    else
-    {
-        // Use the original unsized format when the workaround is required or on top of ES2.
-        return nativegl::GetInternalFormatInfo(formatInfo.format, functions->standard);
-    }
-}
-
 TextureGL::TextureGL(GLenum type,
                      const FunctionsGL *functions,
                      const WorkaroundsGL &workarounds,
@@ -121,18 +95,21 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
-    const nativegl::InternalFormat &nativeInternalFormatInfo =
-        GetNativeInternalFormat(mFunctions, mWorkarounds, internalFormat, type);
+    nativegl::TexImageFormat texImageFormat =
+        nativegl::GetTexImageFormat(mFunctions, mWorkarounds, internalFormat, format, type);
 
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(size.depth == 1);
-        mFunctions->texImage2D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, 0, format, type, pixels);
+        mFunctions->texImage2D(target, level, texImageFormat.internalFormat, size.width,
+                               size.height, 0, texImageFormat.format, texImageFormat.type, pixels);
     }
     else if (UseTexImage3D(mTextureType))
     {
-        mFunctions->texImage3D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, size.depth, 0, format, type, pixels);
+        mFunctions->texImage3D(target, level, texImageFormat.internalFormat, size.width,
+                               size.height, size.depth, 0, texImageFormat.format,
+                               texImageFormat.type, pixels);
     }
     else
     {
@@ -149,16 +126,21 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
+    nativegl::TexSubImageFormat texSubImageFormat =
+        nativegl::GetTexSubImageFormat(mFunctions, mWorkarounds, format, type);
+
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(area.z == 0 && area.depth == 1);
-        mFunctions->texSubImage2D(target, level, area.x, area.y, area.width, area.height, format, type, pixels);
+        mFunctions->texSubImage2D(target, level, area.x, area.y, area.width, area.height,
+                                  texSubImageFormat.format, texSubImageFormat.type, pixels);
     }
     else if (UseTexImage3D(mTextureType))
     {
-        mFunctions->texSubImage3D(target, level, area.x, area.y, area.z, area.width, area.height, area.depth,
-                                  format, type, pixels);
+        mFunctions->texSubImage3D(target, level, area.x, area.y, area.z, area.width, area.height,
+                                  area.depth, texSubImageFormat.format, texSubImageFormat.type,
+                                  pixels);
     }
     else
     {
@@ -175,19 +157,20 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
-    const nativegl::InternalFormat &nativeInternalFormatInfo =
-        GetNativeInternalFormat(mFunctions, mWorkarounds, internalFormat, GL_UNSIGNED_BYTE);
+    nativegl::CompressedTexImageFormat compressedTexImageFormat =
+        nativegl::GetCompressedTexImageFormat(mFunctions, mWorkarounds, internalFormat);
 
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
     {
         ASSERT(size.depth == 1);
-        mFunctions->compressedTexImage2D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, 0, imageSize, pixels);
+        mFunctions->compressedTexImage2D(target, level, compressedTexImageFormat.internalFormat,
+                                         size.width, size.height, 0, imageSize, pixels);
     }
     else if (UseTexImage3D(mTextureType))
     {
-        mFunctions->compressedTexImage3D(target, level, nativeInternalFormatInfo.internalFormat, size.width, size.height, size.depth, 0,
-                                         imageSize, pixels);
+        mFunctions->compressedTexImage3D(target, level, compressedTexImageFormat.internalFormat,
+                                         size.width, size.height, size.depth, 0, imageSize, pixels);
     }
     else
     {
@@ -204,17 +187,21 @@
 
     SetUnpackStateForTexImage(mStateManager, unpack);
 
+    nativegl::CompressedTexSubImageFormat compressedTexSubImageFormat =
+        nativegl::GetCompressedSubTexImageFormat(mFunctions, mWorkarounds, format);
+
     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, pixels);
+                                            compressedTexSubImageFormat.format, 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);
+                                            area.height, area.depth,
+                                            compressedTexSubImageFormat.format, imageSize, pixels);
     }
     else
     {
@@ -227,18 +214,18 @@
 gl::Error TextureGL::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
                                const gl::Framebuffer *source)
 {
-    const nativegl::InternalFormat &nativeInternalFormatInfo = GetNativeInternalFormat(
-        mFunctions, mWorkarounds, internalFormat, source->getImplementationColorReadType());
-
     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
 
     mStateManager->bindTexture(mTextureType, mTextureID);
     mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
 
+    nativegl::CopyTexImageImageFormat copyTexImageFormat = nativegl::GetCopyTexImageImageFormat(
+        mFunctions, mWorkarounds, internalFormat, source->getImplementationColorReadType());
+
     if (UseTexImage2D(mTextureType))
     {
-        mFunctions->copyTexImage2D(target, level, nativeInternalFormatInfo.internalFormat, sourceArea.x, sourceArea.y,
-                                   sourceArea.width, sourceArea.height, 0);
+        mFunctions->copyTexImage2D(target, level, copyTexImageFormat.internalFormat, sourceArea.x,
+                                   sourceArea.y, sourceArea.width, sourceArea.height, 0);
     }
     else
     {
@@ -280,7 +267,8 @@
     // 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);
+    nativegl::TexStorageFormat texStorageFormat =
+        nativegl::GetTexStorageFormat(mFunctions, mWorkarounds, internalFormat);
 
     mStateManager->bindTexture(mTextureType, mTextureID);
     if (UseTexImage2D(mTextureType))
@@ -288,7 +276,8 @@
         ASSERT(size.depth == 1);
         if (mFunctions->texStorage2D)
         {
-            mFunctions->texStorage2D(target, levels, nativeInternalFormatInfo.internalFormat, size.width, size.height);
+            mFunctions->texStorage2D(target, levels, texStorageFormat.internalFormat, size.width,
+                                     size.height);
         }
         else
         {
@@ -311,13 +300,16 @@
                     if (internalFormatInfo.compressed)
                     {
                         size_t dataSize = internalFormatInfo.computeBlockSize(GL_UNSIGNED_BYTE, levelSize.width, levelSize.height);
-                        mFunctions->compressedTexImage2D(target, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
-                                                         0, dataSize, nullptr);
+                        mFunctions->compressedTexImage2D(
+                            target, level, texStorageFormat.internalFormat, levelSize.width,
+                            levelSize.height, 0, dataSize, nullptr);
                     }
                     else
                     {
-                        mFunctions->texImage2D(target, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
-                                               0, internalFormatInfo.format, internalFormatInfo.type, nullptr);
+                        mFunctions->texImage2D(target, level, texStorageFormat.internalFormat,
+                                               levelSize.width, levelSize.height, 0,
+                                               internalFormatInfo.format, internalFormatInfo.type,
+                                               nullptr);
                     }
                 }
                 else if (mTextureType == GL_TEXTURE_CUBE_MAP)
@@ -327,13 +319,16 @@
                         if (internalFormatInfo.compressed)
                         {
                             size_t dataSize = internalFormatInfo.computeBlockSize(GL_UNSIGNED_BYTE, levelSize.width, levelSize.height);
-                            mFunctions->compressedTexImage2D(face, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
-                                                             0, dataSize, nullptr);
+                            mFunctions->compressedTexImage2D(
+                                face, level, texStorageFormat.internalFormat, levelSize.width,
+                                levelSize.height, 0, dataSize, nullptr);
                         }
                         else
                         {
-                            mFunctions->texImage2D(face, level, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height,
-                                                    0, internalFormatInfo.format, internalFormatInfo.type, nullptr);
+                            mFunctions->texImage2D(face, level, texStorageFormat.internalFormat,
+                                                   levelSize.width, levelSize.height, 0,
+                                                   internalFormatInfo.format,
+                                                   internalFormatInfo.type, nullptr);
                         }
                     }
                 }
@@ -348,7 +343,8 @@
     {
         if (mFunctions->texStorage3D)
         {
-            mFunctions->texStorage3D(target, levels, nativeInternalFormatInfo.internalFormat, size.width, size.height, size.depth);
+            mFunctions->texStorage3D(target, levels, texStorageFormat.internalFormat, size.width,
+                                     size.height, size.depth);
         }
         else
         {
@@ -369,13 +365,16 @@
                 if (internalFormatInfo.compressed)
                 {
                     size_t dataSize = internalFormatInfo.computeBlockSize(GL_UNSIGNED_BYTE, levelSize.width, levelSize.height) * levelSize.depth;
-                    mFunctions->compressedTexImage3D(target, i, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height, levelSize.depth,
-                                                     0, dataSize, nullptr);
+                    mFunctions->compressedTexImage3D(target, i, texStorageFormat.internalFormat,
+                                                     levelSize.width, levelSize.height,
+                                                     levelSize.depth, 0, dataSize, nullptr);
                 }
                 else
                 {
-                    mFunctions->texImage3D(target, i, nativeInternalFormatInfo.internalFormat, levelSize.width, levelSize.height, levelSize.depth,
-                                           0, internalFormatInfo.format, internalFormatInfo.type, nullptr);
+                    mFunctions->texImage3D(target, i, texStorageFormat.internalFormat,
+                                           levelSize.width, levelSize.height, levelSize.depth, 0,
+                                           internalFormatInfo.format, internalFormatInfo.type,
+                                           nullptr);
                 }
             }
         }
diff --git a/src/libANGLE/renderer/gl/WorkaroundsGL.h b/src/libANGLE/renderer/gl/WorkaroundsGL.h
index 9a30808..ff8d440 100644
--- a/src/libANGLE/renderer/gl/WorkaroundsGL.h
+++ b/src/libANGLE/renderer/gl/WorkaroundsGL.h
@@ -15,7 +15,7 @@
 struct WorkaroundsGL
 {
     WorkaroundsGL()
-        : avoid1BitAlphaTextureFormats(false)
+        : avoid1BitAlphaTextureFormats(false), rgba4IsNotSupportedForColorRendering(false)
     {
     }
 
@@ -27,6 +27,11 @@
     // drivers on framebuffer formats that have 1-bit alpha, work around this by using higher
     // precision formats instead.
     bool avoid1BitAlphaTextureFormats;
+
+    // On some older Intel drivers, GL_RGBA4 is not color renderable, glCheckFramebufferStatus
+    // returns GL_FRAMEBUFFER_UNSUPPORTED. Work around this by using a known color-renderable
+    // format.
+    bool rgba4IsNotSupportedForColorRendering;
 };
 }
 
diff --git a/src/libANGLE/renderer/gl/formatutilsgl.cpp b/src/libANGLE/renderer/gl/formatutilsgl.cpp
index 78a547d..cf3a14d 100644
--- a/src/libANGLE/renderer/gl/formatutilsgl.cpp
+++ b/src/libANGLE/renderer/gl/formatutilsgl.cpp
@@ -12,6 +12,7 @@
 #include <limits>
 
 #include "common/string_utils.h"
+#include "libANGLE/formatutils.h"
 
 namespace rx
 {
@@ -19,52 +20,6 @@
 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 = InternalFormatConversionMap();;
-        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(),
@@ -156,12 +111,10 @@
                                        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;
@@ -320,6 +273,183 @@
     return defaultInternalFormat;
 }
 
+static GLenum GetNativeInternalFormat(const FunctionsGL *functions,
+                                      const WorkaroundsGL &workarounds,
+                                      GLenum internalFormat,
+                                      GLenum sizedInternalFormat)
+{
+    GLenum result = internalFormat;
+
+    if (functions->standard == STANDARD_GL_DESKTOP)
+    {
+        // Use sized internal formats whenever possible to guarantee the requested precision.
+        // On Desktop GL, passing an internal format of GL_RGBA will generate a GL_RGBA8 texture
+        // even if the provided type is GL_FLOAT.
+        result = sizedInternalFormat;
+
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
+
+        if (workarounds.avoid1BitAlphaTextureFormats && formatInfo.alphaBits == 1)
+        {
+            // Use an 8-bit format instead
+            result = GL_RGBA8;
+        }
+
+        if (workarounds.rgba4IsNotSupportedForColorRendering && sizedInternalFormat == GL_RGBA4)
+        {
+            // Use an 8-bit format instead
+            result = GL_RGBA8;
+        }
+
+        if (sizedInternalFormat == GL_RGB565 && !functions->isAtLeastGL(gl::Version(4, 1)) &&
+            functions->hasGLExtension("GL_ARB_ES2_compatibility"))
+        {
+            // GL_RGB565 is required for basic ES2 functionality but was not added to desktop GL
+            // until 4.1.
+            // Work around this by using an 8-bit format instead.
+            result = GL_RGB8;
+        }
+
+        if (sizedInternalFormat == GL_BGRA8_EXT)
+        {
+            // GLES accepts GL_BGRA as an internal format but desktop GL only accepts it as a type.
+            // Update the internal format to GL_RGBA.
+            result = GL_RGBA8;
+        }
+    }
+    else if (functions->isAtLeastGLES(gl::Version(3, 0)))
+    {
+        result = sizedInternalFormat;
+    }
+
+    return result;
+}
+
+static GLenum GetNativeFormat(const FunctionsGL *functions,
+                              const WorkaroundsGL &workarounds,
+                              GLenum format)
+{
+    GLenum result = format;
+
+    if (functions->standard == STANDARD_GL_DESKTOP)
+    {
+        // The ES SRGB extensions require that the provided format is GL_SRGB or SRGB_ALPHA but
+        // the desktop GL extensions only accept GL_RGB or GL_RGBA.  Convert them.
+        if (format == GL_SRGB)
+        {
+            result = GL_RGB;
+        }
+
+        if (format == GL_SRGB_ALPHA)
+        {
+            result = GL_RGBA;
+        }
+    }
+
+    return result;
+}
+
+static GLenum GetNativeType(const FunctionsGL *functions,
+                            const WorkaroundsGL &workarounds,
+                            GLenum type)
+{
+    GLenum result = type;
+
+    if (functions->standard == STANDARD_GL_DESKTOP)
+    {
+        if (type == GL_HALF_FLOAT_OES)
+        {
+            // The enums differ for the OES half float extensions and desktop GL spec. Update it.
+            result = GL_HALF_FLOAT;
+        }
+    }
+
+    if (functions->isAtLeastGLES(gl::Version(3, 0)))
+    {
+        if (type == GL_HALF_FLOAT_OES)
+        {
+            // The enums differ for the OES half float extensions and ES 3 spec. Update it.
+            result = GL_HALF_FLOAT;
+        }
+    }
+
+    return result;
+}
+
+TexImageFormat GetTexImageFormat(const FunctionsGL *functions,
+                                 const WorkaroundsGL &workarounds,
+                                 GLenum internalFormat,
+                                 GLenum format,
+                                 GLenum type)
+{
+    TexImageFormat result;
+    result.internalFormat = GetNativeInternalFormat(
+        functions, workarounds, internalFormat, gl::GetSizedInternalFormat(internalFormat, type));
+    result.format = GetNativeFormat(functions, workarounds, format);
+    result.type   = GetNativeType(functions, workarounds, type);
+    return result;
+}
+
+TexSubImageFormat GetTexSubImageFormat(const FunctionsGL *functions,
+                                       const WorkaroundsGL &workarounds,
+                                       GLenum format,
+                                       GLenum type)
+{
+    TexSubImageFormat result;
+    result.format = GetNativeFormat(functions, workarounds, format);
+    result.type   = GetNativeType(functions, workarounds, type);
+    return result;
+}
+
+CompressedTexImageFormat GetCompressedTexImageFormat(const FunctionsGL *functions,
+                                                     const WorkaroundsGL &workarounds,
+                                                     GLenum internalFormat)
+{
+    CompressedTexImageFormat result;
+    result.internalFormat = internalFormat;
+    return result;
+}
+
+CompressedTexSubImageFormat GetCompressedSubTexImageFormat(const FunctionsGL *functions,
+                                                           const WorkaroundsGL &workarounds,
+                                                           GLenum format)
+{
+    CompressedTexSubImageFormat result;
+    result.format = format;
+    return result;
+}
+
+CopyTexImageImageFormat GetCopyTexImageImageFormat(const FunctionsGL *functions,
+                                                   const WorkaroundsGL &workarounds,
+                                                   GLenum internalFormat,
+                                                   GLenum framebufferType)
+{
+    CopyTexImageImageFormat result;
+    result.internalFormat =
+        GetNativeInternalFormat(functions, workarounds, internalFormat,
+                                gl::GetSizedInternalFormat(internalFormat, framebufferType));
+    return result;
+}
+
+TexStorageFormat GetTexStorageFormat(const FunctionsGL *functions,
+                                     const WorkaroundsGL &workarounds,
+                                     GLenum internalFormat)
+{
+    TexStorageFormat result;
+    result.internalFormat =
+        GetNativeInternalFormat(functions, workarounds, internalFormat, internalFormat);
+    return result;
+}
+
+RenderbufferFormat GetRenderbufferFormat(const FunctionsGL *functions,
+                                         const WorkaroundsGL &workarounds,
+                                         GLenum internalFormat)
+{
+    RenderbufferFormat result;
+    result.internalFormat =
+        GetNativeInternalFormat(functions, workarounds, internalFormat, internalFormat);
+    return result;
+}
 }
 
 }
diff --git a/src/libANGLE/renderer/gl/formatutilsgl.h b/src/libANGLE/renderer/gl/formatutilsgl.h
index 7c4360f..547d478 100644
--- a/src/libANGLE/renderer/gl/formatutilsgl.h
+++ b/src/libANGLE/renderer/gl/formatutilsgl.h
@@ -17,6 +17,7 @@
 #include "angle_gl.h"
 #include "libANGLE/Version.h"
 #include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/WorkaroundsGL.h"
 
 namespace rx
 {
@@ -42,9 +43,6 @@
 {
     InternalFormat();
 
-    // Internal format to use for the native texture
-    GLenum internalFormat;
-
     SupportRequirement texture;
     SupportRequirement filter;
     SupportRequirement renderbuffer;
@@ -52,6 +50,68 @@
 };
 const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, StandardGL standard);
 
+struct TexImageFormat
+{
+    GLenum internalFormat;
+    GLenum format;
+    GLenum type;
+};
+TexImageFormat GetTexImageFormat(const FunctionsGL *functions,
+                                 const WorkaroundsGL &workarounds,
+                                 GLenum internalFormat,
+                                 GLenum format,
+                                 GLenum type);
+
+struct TexSubImageFormat
+{
+    GLenum format;
+    GLenum type;
+};
+TexSubImageFormat GetTexSubImageFormat(const FunctionsGL *functions,
+                                       const WorkaroundsGL &workarounds,
+                                       GLenum format,
+                                       GLenum type);
+
+struct CompressedTexImageFormat
+{
+    GLenum internalFormat;
+};
+CompressedTexImageFormat GetCompressedTexImageFormat(const FunctionsGL *functions,
+                                                     const WorkaroundsGL &workarounds,
+                                                     GLenum internalFormat);
+
+struct CompressedTexSubImageFormat
+{
+    GLenum format;
+};
+CompressedTexSubImageFormat GetCompressedSubTexImageFormat(const FunctionsGL *functions,
+                                                           const WorkaroundsGL &workarounds,
+                                                           GLenum format);
+
+struct CopyTexImageImageFormat
+{
+    GLenum internalFormat;
+};
+CopyTexImageImageFormat GetCopyTexImageImageFormat(const FunctionsGL *functions,
+                                                   const WorkaroundsGL &workarounds,
+                                                   GLenum internalFormat,
+                                                   GLenum framebufferType);
+
+struct TexStorageFormat
+{
+    GLenum internalFormat;
+};
+TexStorageFormat GetTexStorageFormat(const FunctionsGL *functions,
+                                     const WorkaroundsGL &workarounds,
+                                     GLenum internalFormat);
+
+struct RenderbufferFormat
+{
+    GLenum internalFormat;
+};
+RenderbufferFormat GetRenderbufferFormat(const FunctionsGL *functions,
+                                         const WorkaroundsGL &workarounds,
+                                         GLenum internalFormat);
 }
 
 }
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 1251a3e..371d94a 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -541,6 +541,9 @@
     workarounds->avoid1BitAlphaTextureFormats =
         functions->standard == STANDARD_GL_DESKTOP &&
         (vendor == VENDOR_ID_AMD || vendor == VENDOR_ID_INTEL);
+
+    workarounds->rgba4IsNotSupportedForColorRendering =
+        functions->standard == STANDARD_GL_DESKTOP && vendor == VENDOR_ID_INTEL;
 }
 
 }