Simplify formatutils.h by exposing the info structures.

Removed all the separate query functions and simply expose the internal
info structures.  This reduces the number of std::map/std::set operations
that were hidden behind the API.

Moved the validation tables for ES3 format combinations and effective
internal formats into validationES3.cpp so that formatutils.h only has
generic GL format queries.

BUG=angle:658

Change-Id: Ieb60d42b8eafcdb4f21dcbec130b39478ce5f7c5
Reviewed-on: https://chromium-review.googlesource.com/206835
Reviewed-by: Nicolas Capens <capn@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index d17d67e..e6db5a1 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -754,15 +754,16 @@
 
     RenderbufferStorage *renderbuffer = NULL;
 
-    if (GetDepthBits(internalformat) > 0 && GetStencilBits(internalformat) > 0)
+    const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
+    if (formatInfo.depthBits > 0 && formatInfo.stencilBits > 0)
     {
         renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples);
     }
-    else if (GetDepthBits(internalformat) > 0)
+    else if (formatInfo.depthBits > 0)
     {
         renderbuffer = new gl::Depthbuffer(mRenderer, width, height, samples);
     }
-    else if (GetStencilBits(internalformat) > 0)
+    else if (formatInfo.stencilBits > 0)
     {
         renderbuffer = new gl::Stencilbuffer(mRenderer, width, height, samples);
     }
@@ -1720,9 +1721,9 @@
 {
     gl::Framebuffer *framebuffer = mState.getReadFramebuffer();
 
-    bool isSized = IsSizedInternalFormat(format);
-    GLenum sizedInternalFormat = (isSized ? format : GetSizedInternalFormat(format, type));
-    GLuint outputPitch = GetRowPitch(sizedInternalFormat, type, width, mState.getPackAlignment());
+    GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
+    const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
+    GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, width, mState.getPackAlignment());
 
     mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, mState.getPackState(), pixels);
 }
@@ -2014,9 +2015,12 @@
     FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
     ASSERT(attachment);
 
-    *internalFormat = attachment->getActualFormat();
-    *format = gl::GetFormat(attachment->getActualFormat());
-    *type = gl::GetType(attachment->getActualFormat());
+    GLenum actualFormat = attachment->getActualFormat();
+    const InternalFormat &actualFormatInfo = GetInternalFormatInfo(actualFormat);
+
+    *internalFormat = actualFormat;
+    *format = actualFormatInfo.format;
+    *type = actualFormatInfo.type;
 }
 
 void Context::detachTexture(GLuint texture)
@@ -2501,15 +2505,15 @@
         GLenum format = i->first;
         TextureCaps formatCaps = i->second;
 
-        if (formatCaps.texturable && IsValidInternalFormat(format, mExtensions, clientVersion))
+        const InternalFormat &formatInfo = GetInternalFormatInfo(format);
+        if (formatCaps.texturable && formatInfo.textureSupport(clientVersion, mExtensions))
         {
             // Update the format caps based on the client version and extensions
-            formatCaps.renderable = IsRenderingSupported(format, mExtensions, clientVersion);
-            formatCaps.filterable = IsFilteringSupported(format, mExtensions, clientVersion);
+            formatCaps.renderable = formatInfo.renderSupport(clientVersion, mExtensions);
+            formatCaps.filterable = formatInfo.filterSupport(clientVersion, mExtensions);
 
             // OpenGL ES does not support multisampling with integer formats
-            GLenum componentType = GetComponentType(format);
-            if (componentType == GL_INT || componentType == GL_UNSIGNED_INT)
+            if (formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT)
             {
                 formatCaps.sampleCounts.clear();
             }
diff --git a/src/libGLESv2/Framebuffer.cpp b/src/libGLESv2/Framebuffer.cpp
index f808175..30b042e 100644
--- a/src/libGLESv2/Framebuffer.cpp
+++ b/src/libGLESv2/Framebuffer.cpp
@@ -364,6 +364,7 @@
             GLenum internalformat = colorbuffer->getInternalFormat();
             // TODO(geofflang): use context's texture caps
             const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
+            const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
             if (colorbuffer->isTexture())
             {
                 if (!formatCaps.renderable)
@@ -371,14 +372,14 @@
                     return GL_FRAMEBUFFER_UNSUPPORTED;
                 }
 
-                if (gl::GetDepthBits(internalformat) > 0 || gl::GetStencilBits(internalformat) > 0)
+                if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
                 {
                     return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
                 }
             }
             else
             {
-                if (!formatCaps.renderable || gl::GetDepthBits(internalformat) > 0 || gl::GetStencilBits(internalformat) > 0)
+                if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
                 {
                     return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
                 }
@@ -403,7 +404,7 @@
                 // in GLES 3.0, there is no such restriction
                 if (clientVersion < 3)
                 {
-                    if (gl::GetPixelBytes(colorbuffer->getInternalFormat()) != colorbufferSize)
+                    if (formatInfo.pixelBytes != colorbufferSize)
                     {
                         return GL_FRAMEBUFFER_UNSUPPORTED;
                     }
@@ -427,7 +428,7 @@
                 width = colorbuffer->getWidth();
                 height = colorbuffer->getHeight();
                 samples = colorbuffer->getSamples();
-                colorbufferSize = gl::GetPixelBytes(colorbuffer->getInternalFormat());
+                colorbufferSize = formatInfo.pixelBytes;
                 missingAttachment = false;
             }
         }
@@ -443,10 +444,9 @@
         GLenum internalformat = mDepthbuffer->getInternalFormat();
         // TODO(geofflang): use context's texture caps
         const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
+        const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
         if (mDepthbuffer->isTexture())
         {
-            GLenum internalformat = mDepthbuffer->getInternalFormat();
-
             // depth texture attachments require OES/ANGLE_depth_texture
             // TODO(geofflang): use context's extensions
             if (!mRenderer->getRendererExtensions().depthTextures)
@@ -459,14 +459,14 @@
                 return GL_FRAMEBUFFER_UNSUPPORTED;
             }
 
-            if (gl::GetDepthBits(internalformat) == 0)
+            if (formatInfo.depthBits == 0)
             {
                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
             }
         }
         else
         {
-            if (!formatCaps.renderable || gl::GetDepthBits(internalformat) == 0)
+            if (!formatCaps.renderable || formatInfo.depthBits == 0)
             {
                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
             }
@@ -499,10 +499,9 @@
         GLenum internalformat = mStencilbuffer->getInternalFormat();
         // TODO(geofflang): use context's texture caps
         const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
+        const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
         if (mStencilbuffer->isTexture())
         {
-            GLenum internalformat = mStencilbuffer->getInternalFormat();
-
             // texture stencil attachments come along as part
             // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
             // TODO(geofflang): use context's extensions
@@ -516,14 +515,14 @@
                 return GL_FRAMEBUFFER_UNSUPPORTED;
             }
 
-            if (gl::GetStencilBits(internalformat) == 0)
+            if (formatInfo.stencilBits == 0)
             {
                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
             }
         }
         else
         {
-            if (!formatCaps.renderable || gl::GetStencilBits(internalformat) == 0)
+            if (!formatCaps.renderable || formatInfo.stencilBits == 0)
             {
                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
             }
diff --git a/src/libGLESv2/FramebufferAttachment.cpp b/src/libGLESv2/FramebufferAttachment.cpp
index 5855301..e7855b1 100644
--- a/src/libGLESv2/FramebufferAttachment.cpp
+++ b/src/libGLESv2/FramebufferAttachment.cpp
@@ -33,42 +33,42 @@
 
 GLuint FramebufferAttachment::getRedSize() const
 {
-    return (gl::GetRedBits(getInternalFormat()) > 0) ? gl::GetRedBits(getActualFormat()) : 0;
+    return (GetInternalFormatInfo(getInternalFormat()).redBits > 0) ? GetInternalFormatInfo(getActualFormat()).redBits : 0;
 }
 
 GLuint FramebufferAttachment::getGreenSize() const
 {
-    return (gl::GetGreenBits(getInternalFormat()) > 0) ? gl::GetGreenBits(getActualFormat()) : 0;
+    return (GetInternalFormatInfo(getInternalFormat()).greenBits > 0) ? GetInternalFormatInfo(getActualFormat()).greenBits : 0;
 }
 
 GLuint FramebufferAttachment::getBlueSize() const
 {
-    return (gl::GetBlueBits(getInternalFormat()) > 0) ? gl::GetBlueBits(getActualFormat()) : 0;
+    return (GetInternalFormatInfo(getInternalFormat()).blueBits > 0) ? GetInternalFormatInfo(getActualFormat()).blueBits : 0;
 }
 
 GLuint FramebufferAttachment::getAlphaSize() const
 {
-    return (gl::GetAlphaBits(getInternalFormat()) > 0) ? gl::GetAlphaBits(getActualFormat()) : 0;
+    return (GetInternalFormatInfo(getInternalFormat()).alphaBits > 0) ? GetInternalFormatInfo(getActualFormat()).alphaBits : 0;
 }
 
 GLuint FramebufferAttachment::getDepthSize() const
 {
-    return (gl::GetDepthBits(getInternalFormat()) > 0) ? gl::GetDepthBits(getActualFormat()) : 0;
+    return (GetInternalFormatInfo(getInternalFormat()).depthBits > 0) ? GetInternalFormatInfo(getActualFormat()).depthBits : 0;
 }
 
 GLuint FramebufferAttachment::getStencilSize() const
 {
-    return (gl::GetStencilBits(getInternalFormat()) > 0) ? gl::GetStencilBits(getActualFormat()) : 0;
+    return (GetInternalFormatInfo(getInternalFormat()).stencilBits > 0) ? GetInternalFormatInfo(getActualFormat()).stencilBits : 0;
 }
 
 GLenum FramebufferAttachment::getComponentType() const
 {
-    return gl::GetComponentType(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).componentType;
 }
 
 GLenum FramebufferAttachment::getColorEncoding() const
 {
-    return gl::GetColorEncoding(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).colorEncoding;
 }
 
 bool FramebufferAttachment::isTexture() const
diff --git a/src/libGLESv2/Renderbuffer.cpp b/src/libGLESv2/Renderbuffer.cpp
index d4bfaf2..8f9cfb9 100644
--- a/src/libGLESv2/Renderbuffer.cpp
+++ b/src/libGLESv2/Renderbuffer.cpp
@@ -75,32 +75,32 @@
 
 GLuint Renderbuffer::getRedSize() const
 {
-    return gl::GetRedBits(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).redBits;
 }
 
 GLuint Renderbuffer::getGreenSize() const
 {
-    return gl::GetGreenBits(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).greenBits;
 }
 
 GLuint Renderbuffer::getBlueSize() const
 {
-    return gl::GetBlueBits(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).blueBits;
 }
 
 GLuint Renderbuffer::getAlphaSize() const
 {
-    return gl::GetAlphaBits(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).alphaBits;
 }
 
 GLuint Renderbuffer::getDepthSize() const
 {
-    return gl::GetDepthBits(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).depthBits;
 }
 
 GLuint Renderbuffer::getStencilSize() const
 {
-    return gl::GetStencilBits(getActualFormat());
+    return GetInternalFormatInfo(getActualFormat()).stencilBits;
 }
 
 RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerials(1))
diff --git a/src/libGLESv2/State.cpp b/src/libGLESv2/State.cpp
index b552701..19b5189 100644
--- a/src/libGLESv2/State.cpp
+++ b/src/libGLESv2/State.cpp
@@ -253,7 +253,7 @@
                 return nullClearParam;
             }
 
-            if (GetStencilBits(depthStencil->getActualFormat()) > 0)
+            if (GetInternalFormatInfo(depthStencil->getActualFormat()).stencilBits > 0)
             {
                 clearParams.clearStencil = true;
             }
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 53ebf09..67f9a09 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -190,8 +190,8 @@
 
 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
 {
-    GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
-                                                                       : GetSizedInternalFormat(format, type);
+    GLenum sizedInternalFormat = GetSizedInternalFormat(internalFormat, type);
+
     redefineImage(level, sizedInternalFormat, width, height);
 
     mTexture->setImage(level, width, height, internalFormat, format, type, unpack, pixels);
@@ -238,8 +238,8 @@
 
 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
 {
-    GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
-                                                               : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
+    GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
+
     redefineImage(level, sizedInternalFormat, width, height);
 
     mTexture->copyImage(level, format, x, y, width, height, source);
@@ -254,12 +254,12 @@
 
 bool Texture2D::isCompressed(GLint level) const
 {
-    return IsFormatCompressed(getInternalFormat(level));
+    return GetInternalFormatInfo(getInternalFormat(level)).compressed;
 }
 
 bool Texture2D::isDepth(GLint level) const
 {
-    return GetDepthBits(getInternalFormat(level)) > 0;
+    return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
 }
 
 void Texture2D::generateMipmaps()
@@ -398,12 +398,12 @@
 
 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
 {
-    return IsFormatCompressed(getInternalFormat(target, level));
+    return GetInternalFormatInfo(getInternalFormat(target, level)).compressed;
 }
 
 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
 {
-    return GetDepthBits(getInternalFormat(target, level)) > 0;
+    return GetInternalFormatInfo(getInternalFormat(target, level)).depthBits > 0;
 }
 
 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
@@ -489,12 +489,12 @@
 
 bool Texture3D::isCompressed(GLint level) const
 {
-    return IsFormatCompressed(getInternalFormat(level));
+    return GetInternalFormatInfo(getInternalFormat(level)).compressed;
 }
 
 bool Texture3D::isDepth(GLint level) const
 {
-    return GetDepthBits(getInternalFormat(level)) > 0;
+    return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
 }
 
 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
@@ -594,12 +594,12 @@
 
 bool Texture2DArray::isCompressed(GLint level) const
 {
-    return IsFormatCompressed(getInternalFormat(level));
+    return GetInternalFormatInfo(getInternalFormat(level)).compressed;
 }
 
 bool Texture2DArray::isDepth(GLint level) const
 {
-    return GetDepthBits(getInternalFormat(level)) > 0;
+    return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
 }
 
 void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
diff --git a/src/libGLESv2/formatutils.cpp b/src/libGLESv2/formatutils.cpp
index 8cc2e19..008189a 100644
--- a/src/libGLESv2/formatutils.cpp
+++ b/src/libGLESv2/formatutils.cpp
@@ -22,24 +22,23 @@
 // can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid
 // format and type combinations.
 
-struct FormatTypeInfo
+FormatType::FormatType()
+    : internalFormat(GL_NONE),
+      colorWriteFunction(NULL)
 {
-    GLenum mInternalFormat;
-    ColorWriteFunction mColorWriteFunction;
-
-    FormatTypeInfo(GLenum internalFormat, ColorWriteFunction writeFunc)
-        : mInternalFormat(internalFormat), mColorWriteFunction(writeFunc)
-    { }
-};
+}
 
 typedef std::pair<GLenum, GLenum> FormatTypePair;
-typedef std::pair<FormatTypePair, FormatTypeInfo> FormatPair;
-typedef std::map<FormatTypePair, FormatTypeInfo> FormatMap;
+typedef std::pair<FormatTypePair, FormatType> FormatPair;
+typedef std::map<FormatTypePair, FormatType> FormatMap;
 
 // A helper function to insert data into the format map with fewer characters.
 static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat, ColorWriteFunction writeFunc)
 {
-    map->insert(FormatPair(FormatTypePair(format, type), FormatTypeInfo(internalFormat, writeFunc)));
+    FormatType info;
+    info.internalFormat = internalFormat;
+    info.colorWriteFunction = writeFunc;
+    map->insert(FormatPair(FormatTypePair(format, type), info));
 }
 
 FormatMap BuildFormatMap()
@@ -145,278 +144,59 @@
     return map;
 }
 
-static const FormatMap &GetFormatMap()
+Type::Type()
+    : bytes(0),
+      specialInterpretation(false)
 {
-     static const FormatMap formatMap = BuildFormatMap();
-     return formatMap;
-}
-
-struct FormatInfo
-{
-    GLenum mInternalformat;
-    GLenum mFormat;
-    GLenum mType;
-
-    FormatInfo(GLenum internalformat, GLenum format, GLenum type)
-        : mInternalformat(internalformat), mFormat(format), mType(type) { }
-
-    bool operator<(const FormatInfo& other) const
-    {
-        return memcmp(this, &other, sizeof(FormatInfo)) < 0;
-    }
-};
-
-// ES3 has a specific set of permutations of internal formats, formats and types which are acceptable.
-typedef std::set<FormatInfo> ES3FormatSet;
-
-ES3FormatSet BuildES3FormatSet()
-{
-    ES3FormatSet set;
-
-    // Format combinations from ES 3.0.1 spec, table 3.2
-
-    //                   | Internal format      | Format            | Type                            |
-    //                   |                      |                   |                                 |
-    set.insert(FormatInfo(GL_RGBA8,              GL_RGBA,            GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGB5_A1,            GL_RGBA,            GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGBA4,              GL_RGBA,            GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_SRGB8_ALPHA8,       GL_RGBA,            GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGBA8_SNORM,        GL_RGBA,            GL_BYTE                          ));
-    set.insert(FormatInfo(GL_RGBA4,              GL_RGBA,            GL_UNSIGNED_SHORT_4_4_4_4        ));
-    set.insert(FormatInfo(GL_RGB10_A2,           GL_RGBA,            GL_UNSIGNED_INT_2_10_10_10_REV   ));
-    set.insert(FormatInfo(GL_RGB5_A1,            GL_RGBA,            GL_UNSIGNED_INT_2_10_10_10_REV   ));
-    set.insert(FormatInfo(GL_RGB5_A1,            GL_RGBA,            GL_UNSIGNED_SHORT_5_5_5_1        ));
-    set.insert(FormatInfo(GL_RGBA16F,            GL_RGBA,            GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_RGBA16F,            GL_RGBA,            GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_RGBA32F,            GL_RGBA,            GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RGBA16F,            GL_RGBA,            GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RGBA8UI,            GL_RGBA_INTEGER,    GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGBA8I,             GL_RGBA_INTEGER,    GL_BYTE                          ));
-    set.insert(FormatInfo(GL_RGBA16UI,           GL_RGBA_INTEGER,    GL_UNSIGNED_SHORT                ));
-    set.insert(FormatInfo(GL_RGBA16I,            GL_RGBA_INTEGER,    GL_SHORT                         ));
-    set.insert(FormatInfo(GL_RGBA32UI,           GL_RGBA_INTEGER,    GL_UNSIGNED_INT                  ));
-    set.insert(FormatInfo(GL_RGBA32I,            GL_RGBA_INTEGER,    GL_INT                           ));
-    set.insert(FormatInfo(GL_RGB10_A2UI,         GL_RGBA_INTEGER,    GL_UNSIGNED_INT_2_10_10_10_REV   ));
-    set.insert(FormatInfo(GL_RGB8,               GL_RGB,             GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGB565,             GL_RGB,             GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_SRGB8,              GL_RGB,             GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGB8_SNORM,         GL_RGB,             GL_BYTE                          ));
-    set.insert(FormatInfo(GL_RGB565,             GL_RGB,             GL_UNSIGNED_SHORT_5_6_5          ));
-    set.insert(FormatInfo(GL_R11F_G11F_B10F,     GL_RGB,             GL_UNSIGNED_INT_10F_11F_11F_REV  ));
-    set.insert(FormatInfo(GL_RGB9_E5,            GL_RGB,             GL_UNSIGNED_INT_5_9_9_9_REV      ));
-    set.insert(FormatInfo(GL_RGB16F,             GL_RGB,             GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_RGB16F,             GL_RGB,             GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_R11F_G11F_B10F,     GL_RGB,             GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_R11F_G11F_B10F,     GL_RGB,             GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_RGB9_E5,            GL_RGB,             GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_RGB9_E5,            GL_RGB,             GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_RGB32F,             GL_RGB,             GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RGB16F,             GL_RGB,             GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_R11F_G11F_B10F,     GL_RGB,             GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RGB9_E5,            GL_RGB,             GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RGB8UI,             GL_RGB_INTEGER,     GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGB8I,              GL_RGB_INTEGER,     GL_BYTE                          ));
-    set.insert(FormatInfo(GL_RGB16UI,            GL_RGB_INTEGER,     GL_UNSIGNED_SHORT                ));
-    set.insert(FormatInfo(GL_RGB16I,             GL_RGB_INTEGER,     GL_SHORT                         ));
-    set.insert(FormatInfo(GL_RGB32UI,            GL_RGB_INTEGER,     GL_UNSIGNED_INT                  ));
-    set.insert(FormatInfo(GL_RGB32I,             GL_RGB_INTEGER,     GL_INT                           ));
-    set.insert(FormatInfo(GL_RG8,                GL_RG,              GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RG8_SNORM,          GL_RG,              GL_BYTE                          ));
-    set.insert(FormatInfo(GL_RG16F,              GL_RG,              GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_RG16F,              GL_RG,              GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_RG32F,              GL_RG,              GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RG16F,              GL_RG,              GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_RG8UI,              GL_RG_INTEGER,      GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RG8I,               GL_RG_INTEGER,      GL_BYTE                          ));
-    set.insert(FormatInfo(GL_RG16UI,             GL_RG_INTEGER,      GL_UNSIGNED_SHORT                ));
-    set.insert(FormatInfo(GL_RG16I,              GL_RG_INTEGER,      GL_SHORT                         ));
-    set.insert(FormatInfo(GL_RG32UI,             GL_RG_INTEGER,      GL_UNSIGNED_INT                  ));
-    set.insert(FormatInfo(GL_RG32I,              GL_RG_INTEGER,      GL_INT                           ));
-    set.insert(FormatInfo(GL_R8,                 GL_RED,             GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_R8_SNORM,           GL_RED,             GL_BYTE                          ));
-    set.insert(FormatInfo(GL_R16F,               GL_RED,             GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_R16F,               GL_RED,             GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_R32F,               GL_RED,             GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_R16F,               GL_RED,             GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_R8UI,               GL_RED_INTEGER,     GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_R8I,                GL_RED_INTEGER,     GL_BYTE                          ));
-    set.insert(FormatInfo(GL_R16UI,              GL_RED_INTEGER,     GL_UNSIGNED_SHORT                ));
-    set.insert(FormatInfo(GL_R16I,               GL_RED_INTEGER,     GL_SHORT                         ));
-    set.insert(FormatInfo(GL_R32UI,              GL_RED_INTEGER,     GL_UNSIGNED_INT                  ));
-    set.insert(FormatInfo(GL_R32I,               GL_RED_INTEGER,     GL_INT                           ));
-
-    // Unsized formats
-    set.insert(FormatInfo(GL_RGBA,               GL_RGBA,            GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGBA,               GL_RGBA,            GL_UNSIGNED_SHORT_4_4_4_4        ));
-    set.insert(FormatInfo(GL_RGBA,               GL_RGBA,            GL_UNSIGNED_SHORT_5_5_5_1        ));
-    set.insert(FormatInfo(GL_RGB,                GL_RGB,             GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_RGB,                GL_RGB,             GL_UNSIGNED_SHORT_5_6_5          ));
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_LUMINANCE,          GL_LUMINANCE,       GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_ALPHA,              GL_ALPHA,           GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_SRGB_ALPHA_EXT,     GL_SRGB_ALPHA_EXT,  GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_SRGB_EXT,           GL_SRGB_EXT,        GL_UNSIGNED_BYTE                 ));
-
-    // Depth stencil formats
-    set.insert(FormatInfo(GL_DEPTH_COMPONENT16,  GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT                ));
-    set.insert(FormatInfo(GL_DEPTH_COMPONENT24,  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT                  ));
-    set.insert(FormatInfo(GL_DEPTH_COMPONENT16,  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT                  ));
-    set.insert(FormatInfo(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_DEPTH24_STENCIL8,   GL_DEPTH_STENCIL,   GL_UNSIGNED_INT_24_8             ));
-    set.insert(FormatInfo(GL_DEPTH32F_STENCIL8,  GL_DEPTH_STENCIL,   GL_FLOAT_32_UNSIGNED_INT_24_8_REV));
-
-    // From GL_EXT_sRGB
-    set.insert(FormatInfo(GL_SRGB8_ALPHA8_EXT,   GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE                  ));
-    set.insert(FormatInfo(GL_SRGB8,              GL_SRGB_EXT,       GL_UNSIGNED_BYTE                  ));
-
-    // From GL_OES_texture_float
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_LUMINANCE,          GL_LUMINANCE,       GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_ALPHA,              GL_ALPHA,           GL_FLOAT                         ));
-
-    // From GL_OES_texture_half_float
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_LUMINANCE,          GL_LUMINANCE,       GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_LUMINANCE,          GL_LUMINANCE,       GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_ALPHA,              GL_ALPHA,           GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_ALPHA,              GL_ALPHA,           GL_HALF_FLOAT_OES                ));
-
-    // From GL_EXT_texture_format_BGRA8888
-    set.insert(FormatInfo(GL_BGRA_EXT,           GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 ));
-
-    // From GL_EXT_texture_storage
-    //                   | Internal format          | Format            | Type                            |
-    //                   |                          |                   |                                 |
-    set.insert(FormatInfo(GL_ALPHA8_EXT,             GL_ALPHA,           GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_LUMINANCE8_EXT,         GL_LUMINANCE,       GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_LUMINANCE8_ALPHA8_EXT,  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_ALPHA32F_EXT,           GL_ALPHA,           GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_LUMINANCE32F_EXT,       GL_LUMINANCE,       GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT                         ));
-    set.insert(FormatInfo(GL_ALPHA16F_EXT,           GL_ALPHA,           GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_ALPHA16F_EXT,           GL_ALPHA,           GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_LUMINANCE16F_EXT,       GL_LUMINANCE,       GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_LUMINANCE16F_EXT,       GL_LUMINANCE,       GL_HALF_FLOAT_OES                ));
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT                    ));
-    set.insert(FormatInfo(GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES                ));
-
-    // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888
-    set.insert(FormatInfo(GL_BGRA8_EXT,              GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_BGRA4_ANGLEX,           GL_BGRA_EXT,        GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT));
-    set.insert(FormatInfo(GL_BGRA4_ANGLEX,           GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 ));
-    set.insert(FormatInfo(GL_BGR5_A1_ANGLEX,         GL_BGRA_EXT,        GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT));
-    set.insert(FormatInfo(GL_BGR5_A1_ANGLEX,         GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 ));
-
-    // From GL_ANGLE_depth_texture
-    set.insert(FormatInfo(GL_DEPTH_COMPONENT32_OES,  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES         ));
-
-    // Compressed formats
-    // From ES 3.0.1 spec, table 3.16
-    //                   | Internal format                             | Format                                      | Type           |
-    //                   |                                             |                                             |                |
-    set.insert(FormatInfo(GL_COMPRESSED_R11_EAC,                        GL_COMPRESSED_R11_EAC,                        GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_R11_EAC,                        GL_COMPRESSED_R11_EAC,                        GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_SIGNED_R11_EAC,                 GL_COMPRESSED_SIGNED_R11_EAC,                 GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_RG11_EAC,                       GL_COMPRESSED_RG11_EAC,                       GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_SIGNED_RG11_EAC,                GL_COMPRESSED_SIGNED_RG11_EAC,                GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_RGB8_ETC2,                      GL_COMPRESSED_RGB8_ETC2,                      GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_SRGB8_ETC2,                     GL_COMPRESSED_SRGB8_ETC2,                     GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_UNSIGNED_BYTE));
-
-
-    // From GL_EXT_texture_compression_dxt1
-    set.insert(FormatInfo(GL_COMPRESSED_RGB_S3TC_DXT1_EXT,              GL_COMPRESSED_RGB_S3TC_DXT1_EXT,              GL_UNSIGNED_BYTE));
-    set.insert(FormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,             GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,             GL_UNSIGNED_BYTE));
-
-    // From GL_ANGLE_texture_compression_dxt3
-    set.insert(FormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,           GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,           GL_UNSIGNED_BYTE));
-
-    // From GL_ANGLE_texture_compression_dxt5
-    set.insert(FormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,           GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,           GL_UNSIGNED_BYTE));
-
-    return set;
-}
-
-static const ES3FormatSet &GetES3FormatSet()
-{
-    static const ES3FormatSet es3FormatSet = BuildES3FormatSet();
-    return es3FormatSet;
 }
 
 // Map of sizes of input types
-struct TypeInfo
+typedef std::pair<GLenum, Type> TypeInfoPair;
+typedef std::map<GLenum, Type> TypeInfoMap;
+
+static inline void InsertTypeInfo(TypeInfoMap *map, GLenum type, GLuint bytes, bool specialInterpretation)
 {
-    GLuint mTypeBytes;
-    bool mSpecialInterpretation;
+    Type info;
+    info.bytes = bytes;
+    info.specialInterpretation = specialInterpretation;
 
-    TypeInfo()
-        : mTypeBytes(0), mSpecialInterpretation(false) { }
+    map->insert(std::make_pair(type, info));
+}
 
-    TypeInfo(GLuint typeBytes, bool specialInterpretation)
-        : mTypeBytes(typeBytes), mSpecialInterpretation(specialInterpretation) { }
-
-    bool operator<(const TypeInfo& other) const
-    {
-        return memcmp(this, &other, sizeof(TypeInfo)) < 0;
-    }
-};
-
-typedef std::pair<GLenum, TypeInfo> TypeInfoPair;
-typedef std::map<GLenum, TypeInfo> TypeInfoMap;
+bool operator<(const Type& a, const Type& b)
+{
+    return memcmp(&a, &b, sizeof(Type)) < 0;
+}
 
 static TypeInfoMap BuildTypeInfoMap()
 {
     TypeInfoMap map;
 
-    map.insert(TypeInfoPair(GL_UNSIGNED_BYTE,                  TypeInfo( 1, false)));
-    map.insert(TypeInfoPair(GL_BYTE,                           TypeInfo( 1, false)));
-    map.insert(TypeInfoPair(GL_UNSIGNED_SHORT,                 TypeInfo( 2, false)));
-    map.insert(TypeInfoPair(GL_SHORT,                          TypeInfo( 2, false)));
-    map.insert(TypeInfoPair(GL_UNSIGNED_INT,                   TypeInfo( 4, false)));
-    map.insert(TypeInfoPair(GL_INT,                            TypeInfo( 4, false)));
-    map.insert(TypeInfoPair(GL_HALF_FLOAT,                     TypeInfo( 2, false)));
-    map.insert(TypeInfoPair(GL_HALF_FLOAT_OES,                 TypeInfo( 2, false)));
-    map.insert(TypeInfoPair(GL_FLOAT,                          TypeInfo( 4, false)));
-    map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_5_6_5,           TypeInfo( 2, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_4_4_4_4,         TypeInfo( 2, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_5_5_5_1,         TypeInfo( 2, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, TypeInfo( 2, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, TypeInfo( 2, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_INT_2_10_10_10_REV,    TypeInfo( 4, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_INT_24_8,              TypeInfo( 4, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_INT_10F_11F_11F_REV,   TypeInfo( 4, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_INT_5_9_9_9_REV,       TypeInfo( 4, true )));
-    map.insert(TypeInfoPair(GL_UNSIGNED_INT_24_8_OES,          TypeInfo( 4, true )));
-    map.insert(TypeInfoPair(GL_FLOAT_32_UNSIGNED_INT_24_8_REV, TypeInfo( 8, true )));
+    InsertTypeInfo(&map, GL_UNSIGNED_BYTE,                  1, false);
+    InsertTypeInfo(&map, GL_BYTE,                           1, false);
+    InsertTypeInfo(&map, GL_UNSIGNED_SHORT,                 2, false);
+    InsertTypeInfo(&map, GL_SHORT,                          2, false);
+    InsertTypeInfo(&map, GL_UNSIGNED_INT,                   4, false);
+    InsertTypeInfo(&map, GL_INT,                            4, false);
+    InsertTypeInfo(&map, GL_HALF_FLOAT,                     2, false);
+    InsertTypeInfo(&map, GL_HALF_FLOAT_OES,                 2, false);
+    InsertTypeInfo(&map, GL_FLOAT,                          4, false);
+    InsertTypeInfo(&map, GL_UNSIGNED_SHORT_5_6_5,           2, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_SHORT_4_4_4_4,         2, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_SHORT_5_5_5_1,         2, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, 2, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, 2, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV,    4, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_INT_24_8,              4, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_INT_10F_11F_11F_REV,   4, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_INT_5_9_9_9_REV,       4, true );
+    InsertTypeInfo(&map, GL_UNSIGNED_INT_24_8_OES,          4, true );
+    InsertTypeInfo(&map, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, 8, true );
 
     return map;
 }
 
-static bool GetTypeInfo(GLenum type, TypeInfo *outTypeInfo)
-{
-    static const TypeInfoMap infoMap = BuildTypeInfoMap();
-    TypeInfoMap::const_iterator iter = infoMap.find(type);
-    if (iter != infoMap.end())
-    {
-        if (outTypeInfo)
-        {
-            *outTypeInfo = iter->second;
-        }
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
 // Information about internal formats
-typedef bool(*SupportCheckFunction)(GLuint, const Extensions &);
-
 static bool AlwaysSupported(GLuint, const Extensions &)
 {
     return true;
@@ -469,273 +249,261 @@
     return extensions.*bool1 || extensions.*bool2;
 }
 
-struct InternalFormatInfo
+InternalFormat::InternalFormat()
+    : redBits(0),
+      greenBits(0),
+      blueBits(0),
+      luminanceBits(0),
+      alphaBits(0),
+      sharedBits(0),
+      depthBits(0),
+      stencilBits(0),
+      pixelBytes(0),
+      componentCount(0),
+      compressedBlockWidth(0),
+      compressedBlockHeight(0),
+      format(GL_NONE),
+      type(GL_NONE),
+      componentType(GL_NONE),
+      colorEncoding(GL_NONE),
+      compressed(false),
+      textureSupport(NeverSupported),
+      renderSupport(NeverSupported),
+      filterSupport(NeverSupported)
 {
-    GLuint mRedBits;
-    GLuint mGreenBits;
-    GLuint mBlueBits;
+}
 
-    GLuint mLuminanceBits;
+static InternalFormat UnsizedFormat(GLenum format, InternalFormat::SupportCheckFunction textureSupport,
+                                    InternalFormat::SupportCheckFunction renderSupport,
+                                    InternalFormat::SupportCheckFunction filterSupport)
+{
+    InternalFormat formatInfo;
+    formatInfo.format = format;
+    formatInfo.textureSupport = textureSupport;
+    formatInfo.renderSupport = renderSupport;
+    formatInfo.filterSupport = filterSupport;
+    return formatInfo;
+}
 
-    GLuint mAlphaBits;
-    GLuint mSharedBits;
+static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared,
+                                 GLenum format, GLenum type, GLenum componentType, bool srgb,
+                                 InternalFormat::SupportCheckFunction textureSupport,
+                                 InternalFormat::SupportCheckFunction renderSupport,
+                                 InternalFormat::SupportCheckFunction filterSupport)
+{
+    InternalFormat formatInfo;
+    formatInfo.redBits = red;
+    formatInfo.greenBits = green;
+    formatInfo.blueBits = blue;
+    formatInfo.alphaBits = alpha;
+    formatInfo.sharedBits = shared;
+    formatInfo.pixelBytes = (red + green + blue + alpha + shared) / 8;
+    formatInfo.componentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0);
+    formatInfo.format = format;
+    formatInfo.type = type;
+    formatInfo.componentType = componentType;
+    formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR);
+    formatInfo.textureSupport = textureSupport;
+    formatInfo.renderSupport = renderSupport;
+    formatInfo.filterSupport = filterSupport;
+    return formatInfo;
+}
 
-    GLuint mDepthBits;
-    GLuint mStencilBits;
+static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType,
+                                 InternalFormat::SupportCheckFunction textureSupport,
+                                 InternalFormat::SupportCheckFunction renderSupport,
+                                 InternalFormat::SupportCheckFunction filterSupport)
+{
+    InternalFormat formatInfo;
+    formatInfo.luminanceBits = luminance;
+    formatInfo.alphaBits = alpha;
+    formatInfo.pixelBytes = (luminance + alpha) / 8;
+    formatInfo.componentCount = ((luminance > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0);
+    formatInfo.format = format;
+    formatInfo.type = type;
+    formatInfo.componentType = componentType;
+    formatInfo.colorEncoding = GL_LINEAR;
+    formatInfo.textureSupport = textureSupport;
+    formatInfo.renderSupport = renderSupport;
+    formatInfo.filterSupport = filterSupport;
+    return formatInfo;
+}
 
-    GLuint mPixelBits;
+static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format,
+                                         GLenum type, GLenum componentType, InternalFormat::SupportCheckFunction textureSupport,
+                                         InternalFormat::SupportCheckFunction renderSupport,
+                                         InternalFormat::SupportCheckFunction filterSupport)
+{
+    InternalFormat formatInfo;
+    formatInfo.depthBits = depthBits;
+    formatInfo.stencilBits = stencilBits;
+    formatInfo.pixelBytes = (depthBits + stencilBits + unusedBits) / 8;
+    formatInfo.componentCount = ((depthBits > 0) ? 1 : 0) + ((stencilBits > 0) ? 1 : 0);
+    formatInfo.format = format;
+    formatInfo.type = type;
+    formatInfo.componentType = componentType;
+    formatInfo.colorEncoding = GL_LINEAR;
+    formatInfo.textureSupport = textureSupport;
+    formatInfo.renderSupport = renderSupport;
+    formatInfo.filterSupport = filterSupport;
+    return formatInfo;
+}
 
-    GLuint mComponentCount;
+static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize,
+                                       GLuint componentCount, GLenum format, GLenum type, bool srgb,
+                                       InternalFormat::SupportCheckFunction textureSupport,
+                                       InternalFormat::SupportCheckFunction renderSupport,
+                                       InternalFormat::SupportCheckFunction filterSupport)
+{
+    InternalFormat formatInfo;
+    formatInfo.compressedBlockWidth = compressedBlockWidth;
+    formatInfo.compressedBlockHeight = compressedBlockHeight;
+    formatInfo.pixelBytes = compressedBlockSize / 8;
+    formatInfo.componentCount = componentCount;
+    formatInfo.format = format;
+    formatInfo.type = type;
+    formatInfo.componentType = GL_UNSIGNED_NORMALIZED;
+    formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR);
+    formatInfo.compressed = true;
+    formatInfo.textureSupport = textureSupport;
+    formatInfo.renderSupport = renderSupport;
+    formatInfo.filterSupport = filterSupport;
+    return formatInfo;
+}
 
-    GLuint mCompressedBlockWidth;
-    GLuint mCompressedBlockHeight;
-
-    GLenum mFormat;
-    GLenum mType;
-
-    GLenum mComponentType;
-    GLenum mColorEncoding;
-
-    bool mIsCompressed;
-
-    SupportCheckFunction mTextureSupportFunction;
-    SupportCheckFunction mRenderSupportFunction;
-    SupportCheckFunction mFilterSupportFunction;
-
-    InternalFormatInfo() : mRedBits(0), mGreenBits(0), mBlueBits(0), mLuminanceBits(0), mAlphaBits(0), mSharedBits(0), mDepthBits(0), mStencilBits(0),
-                           mPixelBits(0), mComponentCount(0), mCompressedBlockWidth(0), mCompressedBlockHeight(0), mFormat(GL_NONE), mType(GL_NONE),
-                           mComponentType(GL_NONE), mColorEncoding(GL_NONE), mIsCompressed(false), mTextureSupportFunction(NeverSupported),
-                           mRenderSupportFunction(NeverSupported), mFilterSupportFunction(NeverSupported)
-    {
-    }
-
-    static InternalFormatInfo UnsizedFormat(GLenum format, SupportCheckFunction textureSupport, SupportCheckFunction renderSupport,
-                                            SupportCheckFunction filterSupport)
-    {
-        InternalFormatInfo formatInfo;
-        formatInfo.mFormat = format;
-        formatInfo.mTextureSupportFunction = textureSupport;
-        formatInfo.mRenderSupportFunction = renderSupport;
-        formatInfo.mFilterSupportFunction = filterSupport;
-        return formatInfo;
-    }
-
-    static InternalFormatInfo RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared,
-                                         GLenum format, GLenum type, GLenum componentType, bool srgb,
-                                         SupportCheckFunction textureSupport, SupportCheckFunction renderSupport,
-                                         SupportCheckFunction filterSupport)
-    {
-        InternalFormatInfo formatInfo;
-        formatInfo.mRedBits = red;
-        formatInfo.mGreenBits = green;
-        formatInfo.mBlueBits = blue;
-        formatInfo.mAlphaBits = alpha;
-        formatInfo.mSharedBits = shared;
-        formatInfo.mPixelBits = red + green + blue + alpha + shared;
-        formatInfo.mComponentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0);
-        formatInfo.mFormat = format;
-        formatInfo.mType = type;
-        formatInfo.mComponentType = componentType;
-        formatInfo.mColorEncoding = (srgb ? GL_SRGB : GL_LINEAR);
-        formatInfo.mTextureSupportFunction = textureSupport;
-        formatInfo.mRenderSupportFunction = renderSupport;
-        formatInfo.mFilterSupportFunction = filterSupport;
-        return formatInfo;
-    }
-
-    static InternalFormatInfo LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType,
-                                         SupportCheckFunction textureSupport, SupportCheckFunction renderSupport,
-                                         SupportCheckFunction filterSupport)
-    {
-        InternalFormatInfo formatInfo;
-        formatInfo.mLuminanceBits = luminance;
-        formatInfo.mAlphaBits = alpha;
-        formatInfo.mPixelBits = luminance + alpha;
-        formatInfo.mComponentCount = ((luminance > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0);
-        formatInfo.mFormat = format;
-        formatInfo.mType = type;
-        formatInfo.mComponentType = componentType;
-        formatInfo.mColorEncoding = GL_LINEAR;
-        formatInfo.mTextureSupportFunction = textureSupport;
-        formatInfo.mRenderSupportFunction = renderSupport;
-        formatInfo.mFilterSupportFunction = filterSupport;
-        return formatInfo;
-    }
-
-    static InternalFormatInfo DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format,
-                                                 GLenum type, GLenum componentType, SupportCheckFunction textureSupport,
-                                                 SupportCheckFunction renderSupport, SupportCheckFunction filterSupport)
-    {
-        InternalFormatInfo formatInfo;
-        formatInfo.mDepthBits = depthBits;
-        formatInfo.mStencilBits = stencilBits;
-        formatInfo.mPixelBits = depthBits + stencilBits + unusedBits;
-        formatInfo.mComponentCount = ((depthBits > 0) ? 1 : 0) + ((stencilBits > 0) ? 1 : 0);
-        formatInfo.mFormat = format;
-        formatInfo.mType = type;
-        formatInfo.mComponentType = componentType;
-        formatInfo.mColorEncoding = GL_LINEAR;
-        formatInfo.mTextureSupportFunction = textureSupport;
-        formatInfo.mRenderSupportFunction = renderSupport;
-        formatInfo.mFilterSupportFunction = filterSupport;
-        return formatInfo;
-    }
-
-    static InternalFormatInfo CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize,
-                                               GLuint componentCount, GLenum format, GLenum type, bool srgb,
-                                               SupportCheckFunction textureSupport, SupportCheckFunction renderSupport,
-                                               SupportCheckFunction filterSupport)
-    {
-        InternalFormatInfo formatInfo;
-        formatInfo.mCompressedBlockWidth = compressedBlockWidth;
-        formatInfo.mCompressedBlockHeight = compressedBlockHeight;
-        formatInfo.mPixelBits = compressedBlockSize;
-        formatInfo.mComponentCount = componentCount;
-        formatInfo.mFormat = format;
-        formatInfo.mType = type;
-        formatInfo.mComponentType = GL_UNSIGNED_NORMALIZED;
-        formatInfo.mColorEncoding = (srgb ? GL_SRGB : GL_LINEAR);
-        formatInfo.mIsCompressed = true;
-        formatInfo.mTextureSupportFunction = textureSupport;
-        formatInfo.mRenderSupportFunction = renderSupport;
-        formatInfo.mFilterSupportFunction = filterSupport;
-        return formatInfo;
-    }
-};
-
-typedef std::pair<GLenum, InternalFormatInfo> InternalFormatInfoPair;
-typedef std::map<GLenum, InternalFormatInfo> InternalFormatInfoMap;
+typedef std::pair<GLenum, InternalFormat> InternalFormatInfoPair;
+typedef std::map<GLenum, InternalFormat> InternalFormatInfoMap;
 
 static InternalFormatInfoMap BuildInternalFormatInfoMap()
 {
     InternalFormatInfoMap map;
 
     // From ES 3.0.1 spec, table 3.12
-    map.insert(InternalFormatInfoPair(GL_NONE,              InternalFormatInfo()));
+    map.insert(InternalFormatInfoPair(GL_NONE,              InternalFormat()));
 
-    //                               | Internal format     |                              | R | G | B | A |S | Format         | Type                           | Component type        | SRGB | Texture supported                                    | Renderable      | Filterable    |
-    map.insert(InternalFormatInfoPair(GL_R8,                InternalFormatInfo::RGBAFormat( 8,  0,  0,  0, 0, GL_RED,          GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::textureRG>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_R8_SNORM,          InternalFormatInfo::RGBAFormat( 8,  0,  0,  0, 0, GL_RED,          GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG8,               InternalFormatInfo::RGBAFormat( 8,  8,  0,  0, 0, GL_RG,           GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::textureRG>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG8_SNORM,         InternalFormatInfo::RGBAFormat( 8,  8,  0,  0, 0, GL_RG,           GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB8,              InternalFormatInfo::RGBAFormat( 8,  8,  8,  0, 0, GL_RGB,          GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::rgb8rgba8>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB8_SNORM,        InternalFormatInfo::RGBAFormat( 8,  8,  8,  0, 0, GL_RGB,          GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB565,            InternalFormatInfo::RGBAFormat( 5,  6,  5,  0, 0, GL_RGB,          GL_UNSIGNED_SHORT_5_6_5,         GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>,                                    AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA4,             InternalFormatInfo::RGBAFormat( 4,  4,  4,  4, 0, GL_RGBA,         GL_UNSIGNED_SHORT_4_4_4_4,       GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>,                                    AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB5_A1,           InternalFormatInfo::RGBAFormat( 5,  5,  5,  1, 0, GL_RGBA,         GL_UNSIGNED_SHORT_5_5_5_1,       GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>,                                    AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA8,             InternalFormatInfo::RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA,         GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::rgb8rgba8>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM,       InternalFormatInfo::RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA,         GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB10_A2,          InternalFormatInfo::RGBAFormat(10, 10, 10,  2, 0, GL_RGBA,         GL_UNSIGNED_INT_2_10_10_10_REV,  GL_UNSIGNED_NORMALIZED, false, RequireESVersion<3>,                                    AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB10_A2UI,        InternalFormatInfo::RGBAFormat(10, 10, 10,  2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV,  GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_SRGB8,             InternalFormatInfo::RGBAFormat( 8,  8,  8,  0, 0, GL_RGB,          GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, true,  RequireESVersionOrExtension<3, &Extensions::sRGB>,      NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8,      InternalFormatInfo::RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA,         GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, true,  RequireESVersionOrExtension<3, &Extensions::sRGB>,      AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F,    InternalFormatInfo::RGBAFormat(11, 11, 10,  0, 0, GL_RGB,          GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT,               false, RequireESVersion<3>,                                    RequireExtension<&Extensions::colorBufferFloat>, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB9_E5,           InternalFormatInfo::RGBAFormat( 9,  9,  9,  0, 5, GL_RGB,          GL_UNSIGNED_INT_5_9_9_9_REV,     GL_FLOAT,               false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_R8I,               InternalFormatInfo::RGBAFormat( 8,  0,  0,  0, 0, GL_RED_INTEGER,  GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_R8UI,              InternalFormatInfo::RGBAFormat( 8,  0,  0,  0, 0, GL_RED_INTEGER,  GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_R16I,              InternalFormatInfo::RGBAFormat(16,  0,  0,  0, 0, GL_RED_INTEGER,  GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_R16UI,             InternalFormatInfo::RGBAFormat(16,  0,  0,  0, 0, GL_RED_INTEGER,  GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_R32I,              InternalFormatInfo::RGBAFormat(32,  0,  0,  0, 0, GL_RED_INTEGER,  GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_R32UI,             InternalFormatInfo::RGBAFormat(32,  0,  0,  0, 0, GL_RED_INTEGER,  GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG8I,              InternalFormatInfo::RGBAFormat( 8,  8,  0,  0, 0, GL_RG_INTEGER,   GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG8UI,             InternalFormatInfo::RGBAFormat( 8,  8,  0,  0, 0, GL_RG_INTEGER,   GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG16I,             InternalFormatInfo::RGBAFormat(16, 16,  0,  0, 0, GL_RG_INTEGER,   GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG16UI,            InternalFormatInfo::RGBAFormat(16, 16,  0,  0, 0, GL_RG_INTEGER,   GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG32I,             InternalFormatInfo::RGBAFormat(32, 32,  0,  0, 0, GL_RG_INTEGER,   GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG32UI,            InternalFormatInfo::RGBAFormat(32, 32,  0,  0, 0, GL_RG_INTEGER,   GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB8I,             InternalFormatInfo::RGBAFormat( 8,  8,  8,  0, 0, GL_RGB_INTEGER,  GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB8UI,            InternalFormatInfo::RGBAFormat( 8,  8,  8,  0, 0, GL_RGB_INTEGER,  GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB16I,            InternalFormatInfo::RGBAFormat(16, 16, 16,  0, 0, GL_RGB_INTEGER,  GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB16UI,           InternalFormatInfo::RGBAFormat(16, 16, 16,  0, 0, GL_RGB_INTEGER,  GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB32I,            InternalFormatInfo::RGBAFormat(32, 32, 32,  0, 0, GL_RGB_INTEGER,  GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB32UI,           InternalFormatInfo::RGBAFormat(32, 32, 32,  0, 0, GL_RGB_INTEGER,  GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA8I,            InternalFormatInfo::RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA_INTEGER, GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA8UI,           InternalFormatInfo::RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA16I,           InternalFormatInfo::RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA16UI,          InternalFormatInfo::RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA32I,           InternalFormatInfo::RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA32UI,          InternalFormatInfo::RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    //                               | Internal format     |          | R | G | B | A |S | Format         | Type                           | Component type        | SRGB | Texture supported                                    | Renderable      | Filterable    |
+    map.insert(InternalFormatInfoPair(GL_R8,                RGBAFormat( 8,  0,  0,  0, 0, GL_RED,          GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::textureRG>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_R8_SNORM,          RGBAFormat( 8,  0,  0,  0, 0, GL_RED,          GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG8,               RGBAFormat( 8,  8,  0,  0, 0, GL_RG,           GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::textureRG>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG8_SNORM,         RGBAFormat( 8,  8,  0,  0, 0, GL_RG,           GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB8,              RGBAFormat( 8,  8,  8,  0, 0, GL_RGB,          GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::rgb8rgba8>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB8_SNORM,        RGBAFormat( 8,  8,  8,  0, 0, GL_RGB,          GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB565,            RGBAFormat( 5,  6,  5,  0, 0, GL_RGB,          GL_UNSIGNED_SHORT_5_6_5,         GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>,                                    AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA4,             RGBAFormat( 4,  4,  4,  4, 0, GL_RGBA,         GL_UNSIGNED_SHORT_4_4_4_4,       GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>,                                    AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB5_A1,           RGBAFormat( 5,  5,  5,  1, 0, GL_RGBA,         GL_UNSIGNED_SHORT_5_5_5_1,       GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>,                                    AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA8,             RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA,         GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::rgb8rgba8>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM,       RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA,         GL_BYTE,                         GL_SIGNED_NORMALIZED,   false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB10_A2,          RGBAFormat(10, 10, 10,  2, 0, GL_RGBA,         GL_UNSIGNED_INT_2_10_10_10_REV,  GL_UNSIGNED_NORMALIZED, false, RequireESVersion<3>,                                    AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB10_A2UI,        RGBAFormat(10, 10, 10,  2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV,  GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_SRGB8,             RGBAFormat( 8,  8,  8,  0, 0, GL_RGB,          GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, true,  RequireESVersionOrExtension<3, &Extensions::sRGB>,      NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8,      RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA,         GL_UNSIGNED_BYTE,                GL_UNSIGNED_NORMALIZED, true,  RequireESVersionOrExtension<3, &Extensions::sRGB>,      AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F,    RGBAFormat(11, 11, 10,  0, 0, GL_RGB,          GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT,               false, RequireESVersion<3>,                                    RequireExtension<&Extensions::colorBufferFloat>, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB9_E5,           RGBAFormat( 9,  9,  9,  0, 5, GL_RGB,          GL_UNSIGNED_INT_5_9_9_9_REV,     GL_FLOAT,               false, RequireESVersion<3>,                                    NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_R8I,               RGBAFormat( 8,  0,  0,  0, 0, GL_RED_INTEGER,  GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_R8UI,              RGBAFormat( 8,  0,  0,  0, 0, GL_RED_INTEGER,  GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_R16I,              RGBAFormat(16,  0,  0,  0, 0, GL_RED_INTEGER,  GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_R16UI,             RGBAFormat(16,  0,  0,  0, 0, GL_RED_INTEGER,  GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_R32I,              RGBAFormat(32,  0,  0,  0, 0, GL_RED_INTEGER,  GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_R32UI,             RGBAFormat(32,  0,  0,  0, 0, GL_RED_INTEGER,  GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG8I,              RGBAFormat( 8,  8,  0,  0, 0, GL_RG_INTEGER,   GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG8UI,             RGBAFormat( 8,  8,  0,  0, 0, GL_RG_INTEGER,   GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG16I,             RGBAFormat(16, 16,  0,  0, 0, GL_RG_INTEGER,   GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG16UI,            RGBAFormat(16, 16,  0,  0, 0, GL_RG_INTEGER,   GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG32I,             RGBAFormat(32, 32,  0,  0, 0, GL_RG_INTEGER,   GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG32UI,            RGBAFormat(32, 32,  0,  0, 0, GL_RG_INTEGER,   GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB8I,             RGBAFormat( 8,  8,  8,  0, 0, GL_RGB_INTEGER,  GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB8UI,            RGBAFormat( 8,  8,  8,  0, 0, GL_RGB_INTEGER,  GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB16I,            RGBAFormat(16, 16, 16,  0, 0, GL_RGB_INTEGER,  GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB16UI,           RGBAFormat(16, 16, 16,  0, 0, GL_RGB_INTEGER,  GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB32I,            RGBAFormat(32, 32, 32,  0, 0, GL_RGB_INTEGER,  GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB32UI,           RGBAFormat(32, 32, 32,  0, 0, GL_RGB_INTEGER,  GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    NeverSupported,   NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA8I,            RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA_INTEGER, GL_BYTE,                         GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA8UI,           RGBAFormat( 8,  8,  8,  8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE,                GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA16I,           RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT,                        GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA16UI,          RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT,               GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA32I,           RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT,                          GL_INT,                 false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA32UI,          RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT,                 GL_UNSIGNED_INT,        false, RequireESVersion<3>,                                    AlwaysSupported,  NeverSupported)));
 
-    map.insert(InternalFormatInfoPair(GL_BGRA8_EXT,         InternalFormatInfo::RGBAFormat( 8,  8,  8,  8, 0, GL_BGRA_EXT,     GL_UNSIGNED_BYTE,                  GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX,      InternalFormatInfo::RGBAFormat( 4,  4,  4,  4, 0, GL_BGRA_EXT,     GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX,    InternalFormatInfo::RGBAFormat( 5,  5,  5,  1, 0, GL_BGRA_EXT,     GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_BGRA8_EXT,         RGBAFormat( 8,  8,  8,  8, 0, GL_BGRA_EXT,     GL_UNSIGNED_BYTE,                  GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX,      RGBAFormat( 4,  4,  4,  4, 0, GL_BGRA_EXT,     GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX,    RGBAFormat( 5,  5,  5,  1, 0, GL_BGRA_EXT,     GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported)));
 
     // Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float
-    //                               | Internal format        |                                   | D |S | Format             | Type                           | Comp   | SRGB |  Texture supported                                                                     | Renderable     | Filterable                                          |
-    //                               |                        |                                   |   |  |                    |                                | type   |      |                                                                                        |                |                                                     |
-    map.insert(InternalFormatInfoPair(GL_R16F,              InternalFormatInfo::RGBAFormat(16,  0,  0,  0, 0, GL_RED,          GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
-    map.insert(InternalFormatInfoPair(GL_RG16F,             InternalFormatInfo::RGBAFormat(16, 16,  0,  0, 0, GL_RG,           GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
-    map.insert(InternalFormatInfoPair(GL_RGB16F,            InternalFormatInfo::RGBAFormat(16, 16, 16,  0, 0, GL_RGB,          GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureHalfFloat>,                          AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
-    map.insert(InternalFormatInfoPair(GL_RGBA16F,           InternalFormatInfo::RGBAFormat(16, 16, 16, 16, 0, GL_RGBA,         GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureHalfFloat>,                          AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
-    map.insert(InternalFormatInfoPair(GL_R32F,              InternalFormatInfo::RGBAFormat(32,  0,  0,  0, 0, GL_RED,          GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureFloat, &Extensions::textureRG>,     AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
-    map.insert(InternalFormatInfoPair(GL_RG32F,             InternalFormatInfo::RGBAFormat(32, 32,  0,  0, 0, GL_RG,           GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureFloat, &Extensions::textureRG>,     AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
-    map.insert(InternalFormatInfoPair(GL_RGB32F,            InternalFormatInfo::RGBAFormat(32, 32, 32,  0, 0, GL_RGB,          GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureFloat>,                              AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
-    map.insert(InternalFormatInfoPair(GL_RGBA32F,           InternalFormatInfo::RGBAFormat(32, 32, 32, 32, 0, GL_RGBA,         GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureFloat>,                              AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
+    //                               | Internal format     |          | D |S | Format             | Type                           | Comp   | SRGB |  Texture supported                                                                     | Renderable     | Filterable                                          |
+    //                               |                     |          |   |  |                    |                                | type   |      |                                                                                        |                |                                                     |
+    map.insert(InternalFormatInfoPair(GL_R16F,              RGBAFormat(16,  0,  0,  0, 0, GL_RED,          GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
+    map.insert(InternalFormatInfoPair(GL_RG16F,             RGBAFormat(16, 16,  0,  0, 0, GL_RG,           GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
+    map.insert(InternalFormatInfoPair(GL_RGB16F,            RGBAFormat(16, 16, 16,  0, 0, GL_RGB,          GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureHalfFloat>,                          AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
+    map.insert(InternalFormatInfoPair(GL_RGBA16F,           RGBAFormat(16, 16, 16, 16, 0, GL_RGBA,         GL_HALF_FLOAT,                   GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureHalfFloat>,                          AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>)));
+    map.insert(InternalFormatInfoPair(GL_R32F,              RGBAFormat(32,  0,  0,  0, 0, GL_RED,          GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureFloat, &Extensions::textureRG>,     AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
+    map.insert(InternalFormatInfoPair(GL_RG32F,             RGBAFormat(32, 32,  0,  0, 0, GL_RG,           GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureFloat, &Extensions::textureRG>,     AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
+    map.insert(InternalFormatInfoPair(GL_RGB32F,            RGBAFormat(32, 32, 32,  0, 0, GL_RGB,          GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureFloat>,                              AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
+    map.insert(InternalFormatInfoPair(GL_RGBA32F,           RGBAFormat(32, 32, 32, 32, 0, GL_RGBA,         GL_FLOAT,                        GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureFloat>,                              AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear>    )));
 
     // Depth stencil formats
-    //                               | Internal format         |                                      | D |S | X | Format            | Type                             | Component type        | Supported     |
-    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16,     InternalFormatInfo::DepthStencilFormat(16, 0,  0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT,                 GL_UNSIGNED_NORMALIZED, RequireESVersion<2>,                                                    AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>)));
-    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24,     InternalFormatInfo::DepthStencilFormat(24, 0,  0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,                   GL_UNSIGNED_NORMALIZED, RequireESVersion<3>,                                                    AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>)));
-    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F,    InternalFormatInfo::DepthStencilFormat(32, 0,  0, GL_DEPTH_COMPONENT, GL_FLOAT,                          GL_FLOAT,               RequireESVersion<3>,                                                    AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>)));
-    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, InternalFormatInfo::DepthStencilFormat(32, 0,  0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,                   GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::depthTextures>,                           AlwaysSupported, AlwaysSupported                                           )));
-    map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8,      InternalFormatInfo::DepthStencilFormat(24, 8,  0, GL_DEPTH_STENCIL,   GL_UNSIGNED_INT_24_8,              GL_UNSIGNED_NORMALIZED, RequireESVersionOrExtension<2, &Extensions::depthTextures>,             AlwaysSupported, AlwaysSupported                                           )));
-    map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8,     InternalFormatInfo::DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL,   GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT,               RequireESVersion<3>,                                                    AlwaysSupported, AlwaysSupported                                           )));
-    map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8,        InternalFormatInfo::DepthStencilFormat( 0, 8,  0, GL_DEPTH_STENCIL,   GL_UNSIGNED_BYTE,                  GL_UNSIGNED_INT,        RequireESVersion<2>,                                                    AlwaysSupported, NeverSupported                                            )));
+    //                               | Internal format         |                  | D |S | X | Format            | Type                             | Component type        | Supported     |
+    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16,     DepthStencilFormat(16, 0,  0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT,                 GL_UNSIGNED_NORMALIZED, RequireESVersion<2>,                                                    AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>)));
+    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24,     DepthStencilFormat(24, 0,  0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,                   GL_UNSIGNED_NORMALIZED, RequireESVersion<3>,                                                    AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>)));
+    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F,    DepthStencilFormat(32, 0,  0, GL_DEPTH_COMPONENT, GL_FLOAT,                          GL_FLOAT,               RequireESVersion<3>,                                                    AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>)));
+    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, DepthStencilFormat(32, 0,  0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,                   GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::depthTextures>,                           AlwaysSupported, AlwaysSupported                                           )));
+    map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8,      DepthStencilFormat(24, 8,  0, GL_DEPTH_STENCIL,   GL_UNSIGNED_INT_24_8,              GL_UNSIGNED_NORMALIZED, RequireESVersionOrExtension<2, &Extensions::depthTextures>,             AlwaysSupported, AlwaysSupported                                           )));
+    map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8,     DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL,   GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT,               RequireESVersion<3>,                                                    AlwaysSupported, AlwaysSupported                                           )));
+    map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8,        DepthStencilFormat( 0, 8,  0, GL_DEPTH_STENCIL,   GL_UNSIGNED_BYTE,                  GL_UNSIGNED_INT,        RequireESVersion<2>,                                                    AlwaysSupported, NeverSupported                                            )));
 
     // Luminance alpha formats
-    //                               | Internal format          |                              | L | A | Format            | Type            | Component type        | Supported                                                                    | Renderable    | Filterable    |
-    map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT,             InternalFormatInfo::LUMAFormat( 0,  8, GL_ALPHA,           GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>,                                 NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT,         InternalFormatInfo::LUMAFormat( 8,  0, GL_LUMINANCE,       GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>,                                 NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT,           InternalFormatInfo::LUMAFormat( 0, 32, GL_ALPHA,           GL_FLOAT,         GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>,     NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT,       InternalFormatInfo::LUMAFormat(32,  0, GL_LUMINANCE,       GL_FLOAT,         GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>,     NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT,           InternalFormatInfo::LUMAFormat( 0, 16, GL_ALPHA,           GL_HALF_FLOAT,    GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT,       InternalFormatInfo::LUMAFormat(16,  0, GL_LUMINANCE,       GL_HALF_FLOAT,    GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT,  InternalFormatInfo::LUMAFormat( 8,  8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>,                                 NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, InternalFormatInfo::LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT,         GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>,     NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, InternalFormatInfo::LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT,    GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported)));
+    //                               | Internal format          |          | L | A | Format            | Type            | Component type        | Supported                                                                    | Renderable    | Filterable    |
+    map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT,             LUMAFormat( 0,  8, GL_ALPHA,           GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>,                                 NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT,         LUMAFormat( 8,  0, GL_LUMINANCE,       GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>,                                 NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT,           LUMAFormat( 0, 32, GL_ALPHA,           GL_FLOAT,         GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>,     NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT,       LUMAFormat(32,  0, GL_LUMINANCE,       GL_FLOAT,         GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>,     NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT,           LUMAFormat( 0, 16, GL_ALPHA,           GL_HALF_FLOAT,    GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT,       LUMAFormat(16,  0, GL_LUMINANCE,       GL_HALF_FLOAT,    GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT,  LUMAFormat( 8,  8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>,                                 NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT,         GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>,     NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT,    GL_FLOAT,               RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported)));
 
     // Unsized formats
-    //                               | Internal format   |                                 | Format            | Supported                                                      | Renderable     | Filterable     |
-    map.insert(InternalFormatInfoPair(GL_ALPHA,           InternalFormatInfo::UnsizedFormat(GL_ALPHA,           RequireESVersion<2>,                                             NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE,       InternalFormatInfo::UnsizedFormat(GL_LUMINANCE,       RequireESVersion<2>,                                             NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, InternalFormatInfo::UnsizedFormat(GL_LUMINANCE_ALPHA, RequireESVersion<2>,                                             NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RED,             InternalFormatInfo::UnsizedFormat(GL_RED,             RequireESVersionOrExtension<3, &Extensions::textureRG>,          NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RG,              InternalFormatInfo::UnsizedFormat(GL_RG,              RequireESVersionOrExtension<3, &Extensions::textureRG>,          NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGB,             InternalFormatInfo::UnsizedFormat(GL_RGB,             RequireESVersion<2>,                                             AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RGBA,            InternalFormatInfo::UnsizedFormat(GL_RGBA,            RequireESVersion<2>,                                             AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_RED_INTEGER,     InternalFormatInfo::UnsizedFormat(GL_RED_INTEGER,     RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
-    map.insert(InternalFormatInfoPair(GL_RG_INTEGER,      InternalFormatInfo::UnsizedFormat(GL_RG_INTEGER,      RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
-    map.insert(InternalFormatInfoPair(GL_RGB_INTEGER,     InternalFormatInfo::UnsizedFormat(GL_RGB_INTEGER,     RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
-    map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER,    InternalFormatInfo::UnsizedFormat(GL_RGBA_INTEGER,    RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
-    map.insert(InternalFormatInfoPair(GL_BGRA_EXT,        InternalFormatInfo::UnsizedFormat(GL_BGRA_EXT,        RequireExtension<&Extensions::textureFormatBGRA8888>,            AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, InternalFormatInfo::UnsizedFormat(GL_DEPTH_COMPONENT, RequireESVersion<2>,                                             AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL,   InternalFormatInfo::UnsizedFormat(GL_DEPTH_STENCIL,   RequireESVersionOrExtension<3, &Extensions::packedDepthStencil>, AlwaysSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_SRGB_EXT,        InternalFormatInfo::UnsizedFormat(GL_RGB,             RequireESVersionOrExtension<3, &Extensions::sRGB>,               NeverSupported,  AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT,  InternalFormatInfo::UnsizedFormat(GL_RGBA,            RequireESVersionOrExtension<3, &Extensions::sRGB>,               AlwaysSupported, AlwaysSupported)));
+    //                               | Internal format   |             | Format            | Supported                                                      | Renderable     | Filterable     |
+    map.insert(InternalFormatInfoPair(GL_ALPHA,           UnsizedFormat(GL_ALPHA,           RequireESVersion<2>,                                             NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE,       UnsizedFormat(GL_LUMINANCE,       RequireESVersion<2>,                                             NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, UnsizedFormat(GL_LUMINANCE_ALPHA, RequireESVersion<2>,                                             NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RED,             UnsizedFormat(GL_RED,             RequireESVersionOrExtension<3, &Extensions::textureRG>,          NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RG,              UnsizedFormat(GL_RG,              RequireESVersionOrExtension<3, &Extensions::textureRG>,          NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGB,             UnsizedFormat(GL_RGB,             RequireESVersion<2>,                                             AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RGBA,            UnsizedFormat(GL_RGBA,            RequireESVersion<2>,                                             AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_RED_INTEGER,     UnsizedFormat(GL_RED_INTEGER,     RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
+    map.insert(InternalFormatInfoPair(GL_RG_INTEGER,      UnsizedFormat(GL_RG_INTEGER,      RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
+    map.insert(InternalFormatInfoPair(GL_RGB_INTEGER,     UnsizedFormat(GL_RGB_INTEGER,     RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
+    map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER,    UnsizedFormat(GL_RGBA_INTEGER,    RequireESVersion<3>,                                             NeverSupported,  NeverSupported )));
+    map.insert(InternalFormatInfoPair(GL_BGRA_EXT,        UnsizedFormat(GL_BGRA_EXT,        RequireExtension<&Extensions::textureFormatBGRA8888>,            AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, UnsizedFormat(GL_DEPTH_COMPONENT, RequireESVersion<2>,                                             AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL,   UnsizedFormat(GL_DEPTH_STENCIL,   RequireESVersionOrExtension<3, &Extensions::packedDepthStencil>, AlwaysSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_SRGB_EXT,        UnsizedFormat(GL_RGB,             RequireESVersionOrExtension<3, &Extensions::sRGB>,               NeverSupported,  AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT,  UnsizedFormat(GL_RGBA,            RequireESVersionOrExtension<3, &Extensions::sRGB>,               AlwaysSupported, AlwaysSupported)));
 
     // Compressed formats, From ES 3.0.1 spec, table 3.16
-    //                               | Internal format                             |                                    |W |H | BS |CC| Format                                      | Type            | SRGB | Supported          | Renderable           | Filterable         |
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC,                        InternalFormatInfo::CompressedFormat(4, 4,  64, 1, GL_COMPRESSED_R11_EAC,                        GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC,                 InternalFormatInfo::CompressedFormat(4, 4,  64, 1, GL_COMPRESSED_SIGNED_R11_EAC,                 GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC,                       InternalFormatInfo::CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC,                       GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC,                InternalFormatInfo::CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC,                GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2,                      InternalFormatInfo::CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB8_ETC2,                      GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2,                     InternalFormatInfo::CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_SRGB8_ETC2,                     GL_UNSIGNED_BYTE, true,  UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  InternalFormatInfo::CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, InternalFormatInfo::CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true,  UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC,                 InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_UNSIGNED_BYTE, true,  UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    //                               | Internal format                             |                |W |H | BS |CC| Format                                      | Type            | SRGB | Supported          | Renderable           | Filterable         |
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC,                        CompressedFormat(4, 4,  64, 1, GL_COMPRESSED_R11_EAC,                        GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC,                 CompressedFormat(4, 4,  64, 1, GL_COMPRESSED_SIGNED_R11_EAC,                 GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC,                       CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC,                       GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC,                CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC,                GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2,                      CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB8_ETC2,                      GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2,                     CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_SRGB8_ETC2,                     GL_UNSIGNED_BYTE, true,  UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true,  UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC,                 CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_UNSIGNED_BYTE, true,  UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
 
     // From GL_EXT_texture_compression_dxt1
-    //                               | Internal format                   |                                    |W |H | BS |CC| Format                            | Type            | SRGB | Supported                                           | Renderable           | Filterable         |
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    InternalFormatInfo::CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT1>, NeverSupported,       AlwaysSupported     )));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   InternalFormatInfo::CompressedFormat(4, 4,  64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT1>, NeverSupported,       AlwaysSupported     )));
+    //                               | Internal format                   |                |W |H | BS |CC| Format                            | Type            | SRGB | Supported                                           | Renderable           | Filterable         |
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT1>, NeverSupported,       AlwaysSupported     )));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   CompressedFormat(4, 4,  64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT1>, NeverSupported,       AlwaysSupported     )));
 
     // From GL_ANGLE_texture_compression_dxt3
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT5>, NeverSupported,       AlwaysSupported     )));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT5>, NeverSupported,       AlwaysSupported     )));
 
     // From GL_ANGLE_texture_compression_dxt5
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT5>, NeverSupported,       AlwaysSupported     )));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT5>, NeverSupported,       AlwaysSupported     )));
 
     return map;
 }
@@ -746,24 +514,6 @@
     return formatMap;
 }
 
-static bool GetInternalFormatInfo(GLenum internalFormat, InternalFormatInfo *outFormatInfo)
-{
-    const InternalFormatInfoMap &map = GetInternalFormatMap();
-    InternalFormatInfoMap::const_iterator iter = map.find(internalFormat);
-    if (iter != map.end())
-    {
-        if (outFormatInfo)
-        {
-            *outFormatInfo = iter->second;
-        }
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
 static FormatSet BuildAllSizedInternalFormatSet()
 {
     FormatSet result;
@@ -771,7 +521,7 @@
     const InternalFormatInfoMap &formats = GetInternalFormatMap();
     for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++)
     {
-        if (i->second.mPixelBits > 0)
+        if (i->second.pixelBytes > 0)
         {
             result.insert(i->first);
         }
@@ -780,756 +530,88 @@
     return result;
 }
 
-typedef std::set<GLenum> TypeSet;
-
-struct EffectiveInternalFormatInfo
+const FormatType &GetFormatTypeInfo(GLenum format, GLenum type)
 {
-    GLenum mEffectiveFormat;
-    GLenum mDestFormat;
-    GLuint mMinRedBits;
-    GLuint mMaxRedBits;
-    GLuint mMinGreenBits;
-    GLuint mMaxGreenBits;
-    GLuint mMinBlueBits;
-    GLuint mMaxBlueBits;
-    GLuint mMinAlphaBits;
-    GLuint mMaxAlphaBits;
-
-    EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits,
-                                GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits,
-                                GLuint minAlphaBits, GLuint maxAlphaBits)
-        : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits),
-          mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits),
-          mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits),
-          mMaxAlphaBits(maxAlphaBits) {};
-};
-
-typedef std::vector<EffectiveInternalFormatInfo> EffectiveInternalFormatList;
-
-static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList()
-{
-    EffectiveInternalFormatList list;
-
-    // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
-    //                                                    linear source buffer component sizes.
-    //                                                                            | Source channel min/max sizes |
-    //                                         Effective Internal Format |  N/A   |  R   |  G   |  B   |  A      |
-    list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT,              GL_NONE, 0,  0, 0,  0, 0,  0, 1, 8));
-    list.push_back(EffectiveInternalFormatInfo(GL_R8,                      GL_NONE, 1,  8, 0,  0, 0,  0, 0, 0));
-    list.push_back(EffectiveInternalFormatInfo(GL_RG8,                     GL_NONE, 1,  8, 1,  8, 0,  0, 0, 0));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB565,                  GL_NONE, 1,  5, 1,  6, 1,  5, 0, 0));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB8,                    GL_NONE, 6,  8, 7,  8, 6,  8, 0, 0));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGBA4,                   GL_NONE, 1,  4, 1,  4, 1,  4, 1, 4));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1,                 GL_NONE, 5,  5, 5,  5, 5,  5, 1, 1));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGBA8,                   GL_NONE, 5,  8, 5,  8, 5,  8, 2, 8));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2,                GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2));
-
-    return list;
-}
-
-
-static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList()
-{
-    EffectiveInternalFormatList list;
-
-    // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
-    //                                                    linear source buffer component sizes.
-    //                                                                                        |          Source channel min/max sizes            |
-    //                                         Effective Internal Format |    Dest Format     |     R     |      G     |      B     |      A     |
-    list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT,              GL_ALPHA,           0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1,        8));
-    list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT,          GL_LUMINANCE,       1,        8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX));
-    list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT,   GL_LUMINANCE_ALPHA, 1,        8, 0, UINT_MAX, 0, UINT_MAX, 1,        8));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB565,                  GL_RGB,             1,        5, 1,        6, 1,        5, 0, UINT_MAX));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB8,                    GL_RGB,             6,        8, 7,        8, 6,        8, 0, UINT_MAX));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGBA4,                   GL_RGBA,            1,        4, 1,        4, 1,        4, 1,        4));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1,                 GL_RGBA,            5,        5, 5,        5, 5,        5, 1,        1));
-    list.push_back(EffectiveInternalFormatInfo(GL_RGBA8,                   GL_RGBA,            5,        8, 5,        8, 5,        8, 5,        8));
-
-    return list;
-}
-
-static bool GetEffectiveInternalFormat(const InternalFormatInfo &srcFormat, const InternalFormatInfo &destFormat,
-                                       GLenum *outEffectiveFormat)
-{
-    const EffectiveInternalFormatList *list = NULL;
-    GLenum targetFormat = GL_NONE;
-
-    if (gl::IsSizedInternalFormat(destFormat.mFormat))
+    static const FormatMap formatMap = BuildFormatMap();
+    FormatMap::const_iterator iter = formatMap.find(FormatTypePair(format, type));
+    if (iter != formatMap.end())
     {
-        static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList();
-        list = &sizedList;
+        return iter->second;
     }
     else
     {
-        static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList();
-        list = &unsizedList;
-        targetFormat = destFormat.mFormat;
+        static const FormatType defaultInfo;
+        return defaultInfo;
     }
-
-    for (size_t curFormat = 0; curFormat < list->size(); ++curFormat)
-    {
-        const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat);
-        if ((formatInfo.mDestFormat == targetFormat) &&
-            (formatInfo.mMinRedBits   <= srcFormat.mRedBits   && formatInfo.mMaxRedBits   >= srcFormat.mRedBits)   &&
-            (formatInfo.mMinGreenBits <= srcFormat.mGreenBits && formatInfo.mMaxGreenBits >= srcFormat.mGreenBits) &&
-            (formatInfo.mMinBlueBits  <= srcFormat.mBlueBits  && formatInfo.mMaxBlueBits  >= srcFormat.mBlueBits)  &&
-            (formatInfo.mMinAlphaBits <= srcFormat.mAlphaBits && formatInfo.mMaxAlphaBits >= srcFormat.mAlphaBits))
-        {
-            *outEffectiveFormat = formatInfo.mEffectiveFormat;
-            return true;
-        }
-    }
-
-    return false;
 }
 
-struct CopyConversion
+const Type &GetTypeInfo(GLenum type)
 {
-    GLenum mTextureFormat;
-    GLenum mFramebufferFormat;
-
-    CopyConversion(GLenum textureFormat, GLenum framebufferFormat)
-        : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { }
-
-    bool operator<(const CopyConversion& other) const
+    static const TypeInfoMap infoMap = BuildTypeInfoMap();
+    TypeInfoMap::const_iterator iter = infoMap.find(type);
+    if (iter != infoMap.end())
     {
-        return memcmp(this, &other, sizeof(CopyConversion)) < 0;
-    }
-};
-
-typedef std::set<CopyConversion> CopyConversionSet;
-
-static CopyConversionSet BuildValidES3CopyTexImageCombinations()
-{
-    CopyConversionSet set;
-
-    // From ES 3.0.1 spec, table 3.15
-    set.insert(CopyConversion(GL_ALPHA,           GL_RGBA));
-    set.insert(CopyConversion(GL_LUMINANCE,       GL_RED));
-    set.insert(CopyConversion(GL_LUMINANCE,       GL_RG));
-    set.insert(CopyConversion(GL_LUMINANCE,       GL_RGB));
-    set.insert(CopyConversion(GL_LUMINANCE,       GL_RGBA));
-    set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA));
-    set.insert(CopyConversion(GL_RED,             GL_RED));
-    set.insert(CopyConversion(GL_RED,             GL_RG));
-    set.insert(CopyConversion(GL_RED,             GL_RGB));
-    set.insert(CopyConversion(GL_RED,             GL_RGBA));
-    set.insert(CopyConversion(GL_RG,              GL_RG));
-    set.insert(CopyConversion(GL_RG,              GL_RGB));
-    set.insert(CopyConversion(GL_RG,              GL_RGBA));
-    set.insert(CopyConversion(GL_RGB,             GL_RGB));
-    set.insert(CopyConversion(GL_RGB,             GL_RGBA));
-    set.insert(CopyConversion(GL_RGBA,            GL_RGBA));
-
-    // Necessary for ANGLE back-buffers
-    set.insert(CopyConversion(GL_ALPHA,           GL_BGRA_EXT));
-    set.insert(CopyConversion(GL_LUMINANCE,       GL_BGRA_EXT));
-    set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT));
-    set.insert(CopyConversion(GL_RED,             GL_BGRA_EXT));
-    set.insert(CopyConversion(GL_RG,              GL_BGRA_EXT));
-    set.insert(CopyConversion(GL_RGB,             GL_BGRA_EXT));
-    set.insert(CopyConversion(GL_RGBA,            GL_BGRA_EXT));
-
-    set.insert(CopyConversion(GL_RED_INTEGER,     GL_RED_INTEGER));
-    set.insert(CopyConversion(GL_RED_INTEGER,     GL_RG_INTEGER));
-    set.insert(CopyConversion(GL_RED_INTEGER,     GL_RGB_INTEGER));
-    set.insert(CopyConversion(GL_RED_INTEGER,     GL_RGBA_INTEGER));
-    set.insert(CopyConversion(GL_RG_INTEGER,      GL_RG_INTEGER));
-    set.insert(CopyConversion(GL_RG_INTEGER,      GL_RGB_INTEGER));
-    set.insert(CopyConversion(GL_RG_INTEGER,      GL_RGBA_INTEGER));
-    set.insert(CopyConversion(GL_RGB_INTEGER,     GL_RGB_INTEGER));
-    set.insert(CopyConversion(GL_RGB_INTEGER,     GL_RGBA_INTEGER));
-    set.insert(CopyConversion(GL_RGBA_INTEGER,    GL_RGBA_INTEGER));
-
-    return set;
-}
-
-bool IsValidInternalFormat(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        ASSERT(internalFormatInfo.mTextureSupportFunction != NULL);
-        return internalFormatInfo.mTextureSupportFunction(clientVersion, extensions);
+        return iter->second;
     }
     else
     {
-        return false;
+        static const Type defaultInfo;
+        return defaultInfo;
     }
 }
 
-bool IsValidFormat(GLenum format, const Extensions &extensions, GLuint clientVersion)
+const InternalFormat &GetInternalFormatInfo(GLenum internalFormat)
 {
-    const InternalFormatInfoMap &internalFormats = GetInternalFormatMap();
-    for (InternalFormatInfoMap::const_iterator i = internalFormats.begin(); i != internalFormats.end(); i++)
+    const InternalFormatInfoMap &formatMap = GetInternalFormatMap();
+    InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat);
+    if (iter != formatMap.end())
     {
-        if (i->second.mFormat == format && i->second.mTextureSupportFunction(clientVersion, extensions))
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool IsValidType(GLenum type, const Extensions &extensions, GLuint clientVersion)
-{
-    const InternalFormatInfoMap &internalFormats = GetInternalFormatMap();
-    for (InternalFormatInfoMap::const_iterator i = internalFormats.begin(); i != internalFormats.end(); i++)
-    {
-        if (i->second.mType == type && i->second.mTextureSupportFunction(clientVersion, extensions))
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool IsValidFormatCombination(GLenum internalFormat, GLenum format, GLenum type, const Extensions &extensions, GLuint clientVersion)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        if (!internalFormatInfo.mTextureSupportFunction(clientVersion, extensions))
-        {
-            return false;
-        }
+        return iter->second;
     }
     else
     {
-        UNREACHABLE();
-        return false;
-    }
-
-    if (clientVersion == 2)
-    {
-        static const FormatMap &formats = GetFormatMap();
-        FormatMap::const_iterator iter = formats.find(FormatTypePair(format, type));
-        return (iter != formats.end()) && ((internalFormat == (GLint)type) || (internalFormat == iter->second.mInternalFormat));
-    }
-    else if (clientVersion == 3)
-    {
-        static const ES3FormatSet &formats = GetES3FormatSet();
-        return formats.find(FormatInfo(internalFormat, format, type)) != formats.end();
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
+        static const InternalFormat defaultInternalFormat;
+        return defaultInternalFormat;
     }
 }
 
-bool IsValidCopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle, GLuint clientVersion)
-{
-    InternalFormatInfo textureInternalFormatInfo;
-    InternalFormatInfo framebufferInternalFormatInfo;
-    if (GetInternalFormatInfo(textureInternalFormat, &textureInternalFormatInfo) &&
-        GetInternalFormatInfo(frameBufferInternalFormat, &framebufferInternalFormatInfo))
-    {
-        if (clientVersion == 2)
-        {
-            UNIMPLEMENTED();
-            return false;
-        }
-        else if (clientVersion == 3)
-        {
-            static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations();
-            const CopyConversion conversion = CopyConversion(textureInternalFormatInfo.mFormat,
-                                                             framebufferInternalFormatInfo.mFormat);
-            if (conversionSet.find(conversion) != conversionSet.end())
-            {
-                // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats
-                // must both be signed, unsigned, or fixed point and both source and destinations
-                // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed
-                // conversion between fixed and floating point.
-
-                if ((textureInternalFormatInfo.mColorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.mColorEncoding == GL_SRGB))
-                {
-                    return false;
-                }
-
-                if (((textureInternalFormatInfo.mComponentType == GL_INT) != (framebufferInternalFormatInfo.mComponentType == GL_INT)) ||
-                    ((textureInternalFormatInfo.mComponentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.mComponentType == GL_UNSIGNED_INT)))
-                {
-                    return false;
-                }
-
-                if (gl::IsFloatOrFixedComponentType(textureInternalFormatInfo.mComponentType) &&
-                    !gl::IsFloatOrFixedComponentType(framebufferInternalFormatInfo.mComponentType))
-                {
-                    return false;
-                }
-
-                // GLES specification 3.0.3, sec 3.8.5, pg 139-140:
-                // The effective internal format of the source buffer is determined with the following rules applied in order:
-                //    * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the
-                //      effective internal format is the source buffer's sized internal format.
-                //    * If the source buffer is a texture that was created with an unsized base internal format, then the
-                //      effective internal format is the source image array's effective internal format, as specified by table
-                //      3.12, which is determined from the <format> and <type> that were used when the source image array was
-                //      specified by TexImage*.
-                //    * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where
-                //      Destination Internal Format matches internalformat and where the [source channel sizes] are consistent
-                //      with the values of the source buffer's [channel sizes]. Table 3.17 is used if the
-                //      FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING
-                //      is SRGB.
-                InternalFormatInfo sourceEffectiveFormat;
-                if (readBufferHandle != 0)
-                {
-                    // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer
-                    if (gl::IsSizedInternalFormat(framebufferInternalFormatInfo.mFormat))
-                    {
-                        sourceEffectiveFormat = framebufferInternalFormatInfo;
-                    }
-                    else
-                    {
-                        // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format
-                        // texture. We can use the same table we use when creating textures to get its effective sized format.
-                        GLenum effectiveFormat = gl::GetSizedInternalFormat(framebufferInternalFormatInfo.mFormat,
-                                                                            framebufferInternalFormatInfo.mType);
-                        gl::GetInternalFormatInfo(effectiveFormat, &sourceEffectiveFormat);
-                    }
-                }
-                else
-                {
-                    // The effective internal format must be derived from the source framebuffer's channel sizes.
-                    // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17)
-                    if (framebufferInternalFormatInfo.mColorEncoding == GL_LINEAR)
-                    {
-                        GLenum effectiveFormat;
-                        if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat))
-                        {
-                            gl::GetInternalFormatInfo(effectiveFormat, &sourceEffectiveFormat);
-                        }
-                        else
-                        {
-                            return false;
-                        }
-                    }
-                    else if (framebufferInternalFormatInfo.mColorEncoding == GL_SRGB)
-                    {
-                        // SRGB buffers can only be copied to sized format destinations according to table 3.18
-                        if (gl::IsSizedInternalFormat(textureInternalFormat) &&
-                            (framebufferInternalFormatInfo.mRedBits   >= 1 && framebufferInternalFormatInfo.mRedBits   <= 8) &&
-                            (framebufferInternalFormatInfo.mGreenBits >= 1 && framebufferInternalFormatInfo.mGreenBits <= 8) &&
-                            (framebufferInternalFormatInfo.mBlueBits  >= 1 && framebufferInternalFormatInfo.mBlueBits  <= 8) &&
-                            (framebufferInternalFormatInfo.mAlphaBits >= 1 && framebufferInternalFormatInfo.mAlphaBits <= 8))
-                        {
-                            gl::GetInternalFormatInfo(GL_SRGB8_ALPHA8, &sourceEffectiveFormat);
-                        }
-                        else
-                        {
-                            return false;
-                        }
-                    }
-                    else
-                    {
-                        UNREACHABLE();
-                    }
-                }
-
-                if (gl::IsSizedInternalFormat(textureInternalFormatInfo.mFormat))
-                {
-                    // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized,
-                    // component sizes of the source and destination formats must exactly match
-                    if (textureInternalFormatInfo.mRedBits != sourceEffectiveFormat.mRedBits ||
-                        textureInternalFormatInfo.mGreenBits != sourceEffectiveFormat.mGreenBits ||
-                        textureInternalFormatInfo.mBlueBits != sourceEffectiveFormat.mBlueBits ||
-                        textureInternalFormatInfo.mAlphaBits != sourceEffectiveFormat.mAlphaBits)
-                    {
-                        return false;
-                    }
-                }
-
-
-                return true; // A conversion function exists, and no rule in the specification has precluded conversion
-                             // between these formats.
-            }
-
-            return false;
-        }
-        else
-        {
-            UNREACHABLE();
-            return false;
-        }
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
-    }
-}
-
-bool IsRenderingSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        ASSERT(internalFormatInfo.mTextureSupportFunction != NULL);
-        ASSERT(internalFormatInfo.mRenderSupportFunction != NULL);
-        return internalFormatInfo.mTextureSupportFunction(clientVersion, extensions) &&
-               internalFormatInfo.mRenderSupportFunction(clientVersion, extensions);
-    }
-    else
-    {
-        return false;
-    }
-}
-
-bool IsFilteringSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        ASSERT(internalFormatInfo.mTextureSupportFunction != NULL);
-        ASSERT(internalFormatInfo.mFilterSupportFunction != NULL);
-        return internalFormatInfo.mTextureSupportFunction(clientVersion, extensions) &&
-               internalFormatInfo.mFilterSupportFunction(clientVersion, extensions);
-    }
-    else
-    {
-        return false;
-    }
-}
-
-bool IsSizedInternalFormat(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mPixelBits > 0;
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
-    }
-}
-
-GLenum GetSizedInternalFormat(GLenum format, GLenum type)
-{
-    const FormatMap &formats = GetFormatMap();
-    FormatMap::const_iterator iter = formats.find(FormatTypePair(format, type));
-    return (iter != formats.end()) ? iter->second.mInternalFormat : GL_NONE;
-}
-
-GLuint GetPixelBytes(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mPixelBits / 8;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetAlphaBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mAlphaBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetRedBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mRedBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetGreenBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mGreenBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetBlueBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mBlueBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetLuminanceBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mLuminanceBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetDepthBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mDepthBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetStencilBits(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mStencilBits;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetTypeBytes(GLenum type)
-{
-    TypeInfo typeInfo;
-    if (GetTypeInfo(type, &typeInfo))
-    {
-        return typeInfo.mTypeBytes;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-bool IsSpecialInterpretationType(GLenum type)
-{
-    TypeInfo typeInfo;
-    if (GetTypeInfo(type, &typeInfo))
-    {
-        return typeInfo.mSpecialInterpretation;
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
-    }
-}
-
-bool IsFloatOrFixedComponentType(GLenum type)
-{
-    if (type == GL_UNSIGNED_NORMALIZED ||
-        type == GL_SIGNED_NORMALIZED ||
-        type == GL_FLOAT)
-    {
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
-GLenum GetFormat(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mFormat;
-    }
-    else
-    {
-        UNREACHABLE();
-        return GL_NONE;
-    }
-}
-
-GLenum GetType(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mType;
-    }
-    else
-    {
-        UNREACHABLE();
-        return GL_NONE;
-    }
-}
-
-GLenum GetComponentType(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mComponentType;
-    }
-    else
-    {
-        UNREACHABLE();
-        return GL_NONE;
-    }
-}
-
-GLuint GetComponentCount(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mComponentCount;
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
-    }
-}
-
-GLenum GetColorEncoding(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mColorEncoding;
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
-    }
-}
-
-GLuint GetRowPitch(GLenum internalFormat, GLenum type, GLsizei width, GLint alignment)
+GLuint InternalFormat::computeRowPitch(GLenum type, GLsizei width, GLint alignment) const
 {
     ASSERT(alignment > 0 && isPow2(alignment));
-    return rx::roundUp(GetBlockSize(internalFormat, type, width, 1), static_cast<GLuint>(alignment));
+    return rx::roundUp(computeBlockSize(type, width, 1), static_cast<GLuint>(alignment));
 }
 
-GLuint GetDepthPitch(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height, GLint alignment)
+GLuint InternalFormat::computeDepthPitch(GLenum type, GLsizei width, GLsizei height, GLint alignment) const
 {
-    return GetRowPitch(internalFormat, type, width, alignment) * height;
+    return computeRowPitch(type, width, alignment) * height;
 }
 
-GLuint GetBlockSize(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height)
+GLuint InternalFormat::computeBlockSize(GLenum type, GLsizei width, GLsizei height) const
 {
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
+    if (compressed)
     {
-        if (internalFormatInfo.mIsCompressed)
+        GLsizei numBlocksWide = (width + compressedBlockWidth - 1) / compressedBlockWidth;
+        GLsizei numBlocksHight = (height + compressedBlockHeight - 1) / compressedBlockHeight;
+        return (pixelBytes * numBlocksWide * numBlocksHight);
+    }
+    else
+    {
+        const Type &typeInfo = GetTypeInfo(type);
+        if (typeInfo.specialInterpretation)
         {
-            GLsizei numBlocksWide = (width + internalFormatInfo.mCompressedBlockWidth - 1) / internalFormatInfo.mCompressedBlockWidth;
-            GLsizei numBlocksHight = (height + internalFormatInfo.mCompressedBlockHeight - 1) / internalFormatInfo.mCompressedBlockHeight;
-
-            return (internalFormatInfo.mPixelBits * numBlocksWide * numBlocksHight) / 8;
+            return typeInfo.bytes * width * height;
         }
         else
         {
-            TypeInfo typeInfo;
-            if (GetTypeInfo(type, &typeInfo))
-            {
-                if (typeInfo.mSpecialInterpretation)
-                {
-                    return typeInfo.mTypeBytes * width * height;
-                }
-                else
-                {
-                    return internalFormatInfo.mComponentCount * typeInfo.mTypeBytes * width * height;
-                }
-            }
-            else
-            {
-                UNREACHABLE();
-                return 0;
-            }
+            return componentCount * typeInfo.bytes * width * height;
         }
     }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
 }
 
-bool IsFormatCompressed(GLenum internalFormat)
+GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type)
 {
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mIsCompressed;
-    }
-    else
-    {
-        UNREACHABLE();
-        return false;
-    }
-}
-
-GLuint GetCompressedBlockWidth(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mCompressedBlockWidth;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
-}
-
-GLuint GetCompressedBlockHeight(GLenum internalFormat)
-{
-    InternalFormatInfo internalFormatInfo;
-    if (GetInternalFormatInfo(internalFormat, &internalFormatInfo))
-    {
-        return internalFormatInfo.mCompressedBlockHeight;
-    }
-    else
-    {
-        UNREACHABLE();
-        return 0;
-    }
+    const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat);
+    return (formatInfo.pixelBytes > 0) ? internalFormat : GetFormatTypeInfo(internalFormat, type).internalFormat;
 }
 
 const FormatSet &GetAllSizedInternalFormats()
@@ -1538,11 +620,4 @@
     return formatSet;
 }
 
-ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type)
-{
-    static const FormatMap &formats = GetFormatMap();
-    FormatMap::const_iterator iter = formats.find(FormatTypePair(format, type));
-    return (iter != formats.end()) ? iter->second.mColorWriteFunction : NULL;
-}
-
 }
diff --git a/src/libGLESv2/formatutils.h b/src/libGLESv2/formatutils.h
index fb4d2a3..1fc1c1f 100644
--- a/src/libGLESv2/formatutils.h
+++ b/src/libGLESv2/formatutils.h
@@ -36,53 +36,70 @@
 namespace gl
 {
 
+struct FormatType
+{
+    FormatType();
+
+    GLenum internalFormat;
+    ColorWriteFunction colorWriteFunction;
+};
+const FormatType &GetFormatTypeInfo(GLenum format, GLenum type);
+
+struct Type
+{
+    Type();
+
+    GLuint bytes;
+    bool specialInterpretation;
+};
+const Type &GetTypeInfo(GLenum type);
+
+struct InternalFormat
+{
+    InternalFormat();
+
+    GLuint redBits;
+    GLuint greenBits;
+    GLuint blueBits;
+
+    GLuint luminanceBits;
+
+    GLuint alphaBits;
+    GLuint sharedBits;
+
+    GLuint depthBits;
+    GLuint stencilBits;
+
+    GLuint pixelBytes;
+
+    GLuint componentCount;
+
+    bool compressed;
+    GLuint compressedBlockWidth;
+    GLuint compressedBlockHeight;
+
+    GLenum format;
+    GLenum type;
+
+    GLenum componentType;
+    GLenum colorEncoding;
+
+    typedef bool (*SupportCheckFunction)(GLuint, const Extensions &);
+    SupportCheckFunction textureSupport;
+    SupportCheckFunction renderSupport;
+    SupportCheckFunction filterSupport;
+
+    GLuint computeRowPitch(GLenum type, GLsizei width, GLint alignment) const;
+    GLuint computeDepthPitch(GLenum type, GLsizei width, GLsizei height, GLint alignment) const;
+    GLuint computeBlockSize(GLenum type, GLsizei width, GLsizei height) const;
+};
+const InternalFormat &GetInternalFormatInfo(GLenum internalFormat);
+
+GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type);
+
 typedef std::set<GLenum> FormatSet;
-
-bool IsValidInternalFormat(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion);
-bool IsValidFormat(GLenum format, const Extensions &extensions, GLuint clientVersion);
-bool IsValidType(GLenum type, const Extensions &extensions, GLuint clientVersion);
-
-bool IsValidFormatCombination(GLenum internalFormat, GLenum format, GLenum type, const Extensions &extensions, GLuint clientVersion);
-bool IsValidCopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle, GLuint clientVersion);
-
-bool IsRenderingSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion);
-bool IsFilteringSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion);
-
-bool IsSizedInternalFormat(GLenum internalFormat);
-GLenum GetSizedInternalFormat(GLenum format, GLenum type);
-
-GLuint GetPixelBytes(GLenum internalFormat);
-GLuint GetAlphaBits(GLenum internalFormat);
-GLuint GetRedBits(GLenum internalFormat);
-GLuint GetGreenBits(GLenum internalFormat);
-GLuint GetBlueBits(GLenum internalFormat);
-GLuint GetLuminanceBits(GLenum internalFormat);
-GLuint GetDepthBits(GLenum internalFormat);
-GLuint GetStencilBits(GLenum internalFormat);
-
-GLuint GetTypeBytes(GLenum type);
-bool IsSpecialInterpretationType(GLenum type);
-bool IsFloatOrFixedComponentType(GLenum type);
-
-GLenum GetFormat(GLenum internalFormat);
-GLenum GetType(GLenum internalFormat);
-
-GLenum GetComponentType(GLenum internalFormat);
-GLuint GetComponentCount(GLenum internalFormat);
-GLenum GetColorEncoding(GLenum internalFormat);
-
-GLuint GetRowPitch(GLenum internalFormat, GLenum type, GLsizei width, GLint alignment);
-GLuint GetDepthPitch(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height, GLint alignment);
-GLuint GetBlockSize(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height);
-
-bool IsFormatCompressed(GLenum internalFormat);
-GLuint GetCompressedBlockWidth(GLenum internalFormat);
-GLuint GetCompressedBlockHeight(GLenum internalFormat);
-
 const FormatSet &GetAllSizedInternalFormats();
 
-ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type);
-
 }
 
 #endif LIBGLESV2_FORMATUTILS_H_
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 5561c7b..73f4572 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -716,7 +716,8 @@
             return;
         }
 
-        if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(internalformat, GL_UNSIGNED_BYTE, width, height))
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
         {
             return gl::error(GL_INVALID_VALUE);
         }
@@ -774,7 +775,8 @@
             return;
         }
 
-        if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, width, height))
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
         {
             return gl::error(GL_INVALID_VALUE);
         }
@@ -1602,6 +1604,7 @@
 
         GLenum internalFormat = texture->getBaseLevelInternalFormat();
         const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
 
         // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
         // unsized formats or that are color renderable and filterable.  Since we do not track if
@@ -1615,14 +1618,14 @@
                       internalFormat == GL_LUMINANCE8_ALPHA8_EXT ||
                       internalFormat == GL_ALPHA8_EXT;
 
-        if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0 || !formatCaps.filterable ||
-            (!formatCaps.renderable && !isLUMA) || gl::IsFormatCompressed(internalFormat))
+        if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
+            (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
         {
             return gl::error(GL_INVALID_OPERATION);
         }
 
         // GL_EXT_sRGB does not support mipmap generation on sRGB textures
-        if (context->getClientVersion() == 2 && gl::GetColorEncoding(internalFormat) == GL_SRGB)
+        if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
         {
             return gl::error(GL_INVALID_OPERATION);
         }
@@ -4974,7 +4977,8 @@
             return gl::error(GL_INVALID_OPERATION);
         }
 
-        if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(internalformat, GL_UNSIGNED_BYTE, width, height))
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
         {
             return gl::error(GL_INVALID_VALUE);
         }
@@ -5024,7 +5028,8 @@
             return gl::error(GL_INVALID_OPERATION);
         }
 
-        if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, width, height))
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
         {
             return gl::error(GL_INVALID_VALUE);
         }
diff --git a/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/libGLESv2/renderer/IndexRangeCache.cpp
index 14410d0..4fdb0ca 100644
--- a/src/libGLESv2/renderer/IndexRangeCache.cpp
+++ b/src/libGLESv2/renderer/IndexRangeCache.cpp
@@ -31,7 +31,7 @@
     while (i != mIndexRangeCache.end())
     {
         unsigned int rangeStart = i->second.streamOffset;
-        unsigned int rangeEnd = i->second.streamOffset + (gl::GetTypeBytes(i->first.type) * i->first.count);
+        unsigned int rangeEnd = i->second.streamOffset + (gl::GetTypeInfo(i->first.type).bytes * i->first.count);
 
         if (invalidateEnd < rangeStart || invalidateStart > rangeEnd)
         {
diff --git a/src/libGLESv2/renderer/d3d/IndexDataManager.cpp b/src/libGLESv2/renderer/d3d/IndexDataManager.cpp
index d6de3bf..98716c1 100644
--- a/src/libGLESv2/renderer/d3d/IndexDataManager.cpp
+++ b/src/libGLESv2/renderer/d3d/IndexDataManager.cpp
@@ -131,7 +131,10 @@
         return GL_OUT_OF_MEMORY;
     }
 
+    const gl::Type &typeInfo = gl::GetTypeInfo(type);
+
     GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+
     unsigned int offset = 0;
     bool alignedOffset = false;
 
@@ -155,16 +158,14 @@
           default: UNREACHABLE(); alignedOffset = false;
         }
 
-        unsigned int typeSize = gl::GetTypeBytes(type);
-
         // check for integer overflows
-        if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
-            typeSize * static_cast<unsigned int>(count) + offset < offset)
+        if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeInfo.bytes) ||
+            typeInfo.bytes * static_cast<unsigned int>(count) + offset < offset)
         {
             return GL_OUT_OF_MEMORY;
         }
 
-        if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
+        if (typeInfo.bytes * static_cast<unsigned int>(count) + offset > storage->getSize())
         {
             return GL_INVALID_OPERATION;
         }
@@ -197,7 +198,7 @@
         if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
                                                            &translated->maxIndex, &streamOffset))
         {
-            streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
+            streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
                                                          translated->maxIndex, streamOffset);
@@ -217,6 +218,8 @@
         indexBuffer = NULL;
     }
 
+    const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
+
     if (!directStorage && !indexBuffer)
     {
         indexBuffer = (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
@@ -228,7 +231,7 @@
             if (staticBuffer->getBufferSize() == 0 && alignedOffset)
             {
                 indexBuffer = staticBuffer;
-                convertCount = storage->getSize() / gl::GetTypeBytes(type);
+                convertCount = storage->getSize() / typeInfo.bytes;
             }
             else
             {
@@ -243,14 +246,13 @@
             return GL_INVALID_OPERATION;
         }
 
-        unsigned int indexTypeSize = gl::GetTypeBytes(destinationIndexType);
-        if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
+        if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
         {
-            ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
+            ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, destTypeInfo.bytes);
             return GL_OUT_OF_MEMORY;
         }
 
-        unsigned int bufferSizeRequired = convertCount * indexTypeSize;
+        unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
         if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
         {
             ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
@@ -274,7 +276,7 @@
 
         if (staticBuffer)
         {
-            streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
+            streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
                                                          translated->maxIndex, streamOffset);
         }
@@ -283,13 +285,13 @@
     translated->storage = directStorage ? storage : NULL;
     translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
     translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
-    translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType);
+    translated->startIndex = streamOffset / destTypeInfo.bytes;
     translated->startOffset = streamOffset;
     translated->indexType = destinationIndexType;
 
     if (storage)
     {
-        storage->promoteStaticUsage(count * gl::GetTypeBytes(type));
+        storage->promoteStaticUsage(count * typeInfo.bytes);
     }
 
     return GL_NO_ERROR;
diff --git a/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
index a813422..4cbe5d6 100644
--- a/src/libGLESv2/renderer/d3d/TextureD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
@@ -295,13 +295,13 @@
 
 bool TextureD3D_2D::isDepth(GLint level) const
 {
-    return gl::GetDepthBits(getInternalFormat(level)) > 0;
+    return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
 }
 
 void TextureD3D_2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
 {
-    GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
-                                                                       : gl::GetSizedInternalFormat(format, type);
+    GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
+
     bool fastUnpacked = false;
 
     // Attempt a fast gpu copy of the pixel data to the surface
@@ -414,7 +414,7 @@
             sourceRect.height = height;
 
             mRenderer->copyImage(source, sourceRect,
-                                 gl::GetFormat(getBaseLevelInternalFormat()),
+                                 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
                                  xoffset, yoffset, mTexStorage, level);
         }
     }
@@ -492,7 +492,8 @@
     // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
     // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
     // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
-    if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(0));
+    if (formatInfo.depthBits > 0 && mRenderer->getCurrentClientVersion() > 2)
     {
         if (samplerState.compareMode == GL_NONE)
         {
@@ -886,13 +887,12 @@
 
 bool TextureD3D_Cube::isDepth(GLenum target, GLint level) const
 {
-    return gl::GetDepthBits(getInternalFormat(target, level)) > 0;
+    return gl::GetInternalFormatInfo(getInternalFormat(target, level)).depthBits > 0;
 }
 
 void TextureD3D_Cube::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
 {
-    GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
-                                                                       : gl::GetSizedInternalFormat(format, type);
+    GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
 
     redefineImage(faceIndex, level, sizedInternalFormat, width, height);
 
@@ -929,8 +929,8 @@
 void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     int faceIndex = targetToIndex(target);
-    GLenum sizedInternalFormat = gl::IsSizedInternalFormat(format) ? format
-                                                               : gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
+    GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
+
     redefineImage(faceIndex, level, sizedInternalFormat, width, height);
 
     if (!mImageArray[faceIndex][level]->isRenderableFormat())
@@ -986,7 +986,7 @@
             sourceRect.y = y;
             sourceRect.height = height;
 
-            mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
+            mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
                                  xoffset, yoffset, mTexStorage, target, level);
         }
     }
@@ -1502,13 +1502,13 @@
 
 bool TextureD3D_3D::isDepth(GLint level) const
 {
-    return gl::GetDepthBits(getInternalFormat(level)) > 0;
+    return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
 }
 
 void TextureD3D_3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
 {
-    GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
-                                                                       : gl::GetSizedInternalFormat(format, type);
+    GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
+
     redefineImage(level, sizedInternalFormat, width, height, depth);
 
     bool fastUnpacked = false;
@@ -1602,7 +1602,7 @@
             sourceRect.height = height;
 
             mRenderer->copyImage(source, sourceRect,
-                                 gl::GetFormat(getBaseLevelInternalFormat()),
+                                 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
                                  xoffset, yoffset, zoffset, mTexStorage, level);
         }
     }
@@ -2045,16 +2045,17 @@
 
 bool TextureD3D_2DArray::isDepth(GLint level) const
 {
-    return gl::GetDepthBits(getInternalFormat(level)) > 0;
+    return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
 }
 
 void TextureD3D_2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
 {
-    GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
-                                                                       : gl::GetSizedInternalFormat(format, type);
+    GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
+
     redefineImage(level, sizedInternalFormat, width, height, depth);
 
-    GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
 
     for (int i = 0; i < depth; i++)
     {
@@ -2068,7 +2069,8 @@
     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
     redefineImage(level, format, width, height, depth);
 
-    GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
 
     for (int i = 0; i < depth; i++)
     {
@@ -2079,8 +2081,8 @@
 
 void TextureD3D_2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
 {
-    GLenum internalformat = getInternalFormat(level);
-    GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
 
     for (int i = 0; i < depth; i++)
     {
@@ -2096,7 +2098,8 @@
 
 void TextureD3D_2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
 {
-    GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
 
     for (int i = 0; i < depth; i++)
     {
@@ -2135,7 +2138,7 @@
             sourceRect.y = y;
             sourceRect.height = height;
 
-            mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)),
+            mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
                                  xoffset, yoffset, zoffset, mTexStorage, level);
         }
     }
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp
index 446149c..f43c767 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp
@@ -377,10 +377,10 @@
 
     D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc;
     source->GetDesc(&sourceSRVDesc);
-    GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(sourceSRVDesc.Format);
+    const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3d11_gl::GetInternalFormat(sourceSRVDesc.Format));
 
     GLenum shaderType = GL_NONE;
-    switch (gl::GetComponentType(sourceInternalFormat))
+    switch (sourceFormatInfo.componentType)
     {
       case GL_UNSIGNED_NORMALIZED:
       case GL_SIGNED_NORMALIZED:
@@ -520,7 +520,7 @@
 
     BlitParameters parameters = { 0 };
     parameters.mDestinationFormat = destFormat;
-    parameters.mSignedInteger = gl::GetComponentType(sourceInternalFormat) == GL_INT;
+    parameters.mSignedInteger = gl::GetInternalFormatInfo(sourceInternalFormat).componentType == GL_INT;
     parameters.m3DBlit = sourceArea.depth > 1;
 
     BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters);
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
index 656cd94..1d20fd9 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
@@ -219,34 +219,29 @@
                     return;
                 }
 
-                GLenum internalFormat = attachment->getInternalFormat();
-                GLenum actualFormat = attachment->getActualFormat();
-                GLenum componentType = gl::GetComponentType(internalFormat);
+                const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat());
+
                 if (clearParams.colorClearType == GL_FLOAT &&
-                    !(componentType == GL_FLOAT || componentType == GL_UNSIGNED_NORMALIZED || componentType == GL_SIGNED_NORMALIZED))
+                    !(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED))
                 {
                     ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-"
-                        "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, internalFormat);
+                        "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment,
+                        attachment->getInternalFormat());
                 }
 
-                GLuint internalRedBits = gl::GetRedBits(internalFormat);
-                GLuint internalGreenBits = gl::GetGreenBits(internalFormat);
-                GLuint internalBlueBits = gl::GetBlueBits(internalFormat);
-                GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat);
-
-                if ((internalRedBits   == 0 || !clearParams.colorMaskRed) &&
-                    (internalGreenBits == 0 || !clearParams.colorMaskGreen) &&
-                    (internalBlueBits  == 0 || !clearParams.colorMaskBlue) &&
-                    (internalAlphaBits == 0 || !clearParams.colorMaskAlpha))
+                if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) &&
+                    (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) &&
+                    (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) &&
+                    (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha))
                 {
                     // Every channel either does not exist in the render target or is masked out
                     continue;
                 }
                 else if (needScissoredClear || clearParams.colorClearType != GL_FLOAT ||
-                         (internalRedBits   > 0 && !clearParams.colorMaskRed)   ||
-                         (internalGreenBits > 0 && !clearParams.colorMaskGreen) ||
-                         (internalBlueBits  > 0 && !clearParams.colorMaskBlue)  ||
-                         (internalAlphaBits > 0 && !clearParams.colorMaskAlpha))
+                         (formatInfo.redBits   > 0 && !clearParams.colorMaskRed)   ||
+                         (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
+                         (formatInfo.blueBits  > 0 && !clearParams.colorMaskBlue) ||
+                         (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
                 {
                     // A scissored or masked clear is required
                     MaskedRenderTarget maskAndRt;
@@ -269,19 +264,16 @@
                         return;
                     }
 
+                    const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat());
+
                     // Check if the actual format has a channel that the internal format does not and set them to the
                     // default values
-                    GLuint actualRedBits   = gl::GetRedBits(actualFormat);
-                    GLuint actualGreenBits = gl::GetGreenBits(actualFormat);
-                    GLuint actualBlueBits  = gl::GetBlueBits(actualFormat);
-                    GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat);
-
                     const float clearValues[4] =
                     {
-                        ((internalRedBits   == 0 && actualRedBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
-                        ((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
-                        ((internalBlueBits  == 0 && actualBlueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue),
-                        ((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
+                        ((formatInfo.redBits == 0 && actualFormatInfo.redBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
+                        ((formatInfo.greenBits == 0 && actualFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
+                        ((formatInfo.blueBits == 0 && actualFormatInfo.blueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue),
+                        ((formatInfo.alphaBits == 0 && actualFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
                     };
 
                     deviceContext->ClearRenderTargetView(framebufferRTV, clearValues);
@@ -302,9 +294,9 @@
                 return;
             }
 
-            GLenum actualFormat = attachment->getActualFormat();
+            const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat());
 
-            unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << gl::GetStencilBits(actualFormat)) - 1 : 0;
+            unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << actualFormatInfo.stencilBits) - 1 : 0;
             bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
 
             if (needScissoredClear || needMaskedStencilClear)
@@ -463,12 +455,12 @@
         if (i < rts.size())
         {
             RenderTarget11 *rt = rts[i].renderTarget;
-            GLint internalFormat = rt->getInternalFormat();
+            const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat());
 
-            blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && gl::GetRedBits(internalFormat)   > 0);
-            blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && gl::GetGreenBits(internalFormat) > 0);
-            blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && gl::GetBlueBits(internalFormat)  > 0);
-            blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && gl::GetAlphaBits(internalFormat) > 0);
+            blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits   > 0);
+            blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0);
+            blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits  > 0);
+            blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0);
         }
         else
         {
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
index 2165bec..c95f7a4 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
@@ -153,8 +153,9 @@
 void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLint unpackAlignment, GLenum type, const void *input)
 {
-    GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, width, unpackAlignment);
-    GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, type, width, height, unpackAlignment);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+    GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment);
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpackAlignment);
     GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
 
     LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type);
@@ -179,8 +180,9 @@
 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                  const void *input)
 {
-    GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, 1);
-    GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, height, 1);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+    GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1);
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
 
     GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
     GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat);
@@ -287,13 +289,12 @@
         }
 
         // determine the offset coordinate into the destination buffer
-        GLsizei rowOffset = gl::GetPixelBytes(mActualFormat) * xoffset;
+        GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset;
         void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
 
-        GLenum format = gl::GetFormat(mInternalFormat);
-        GLenum type = gl::GetType(mInternalFormat);
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
 
-        mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
+        mRenderer->readPixels(source, x, y, width, height, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
 
         unmap();
     }
diff --git a/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp
index 1ca456c..2e972f2 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp
@@ -122,7 +122,7 @@
     float texelCenterX = 0.5f / static_cast<float>(destSize.width - 1);
     float texelCenterY = 0.5f / static_cast<float>(destSize.height - 1);
 
-    unsigned int bytesPerPixel = gl::GetPixelBytes(internalFormat);
+    unsigned int bytesPerPixel = gl::GetInternalFormatInfo(internalFormat).pixelBytes;
     unsigned int alignmentBytes = static_cast<unsigned int>(unpack.alignment);
     unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel);
 
@@ -157,8 +157,8 @@
 
     // The SRV must be in the proper read format, which may be different from the destination format
     // EG: for half float data, we can load full precision floats with implicit conversion
-    GLenum unsizedFormat = gl::GetFormat(destinationFormat);
-    GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType);
+    GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format;
+    GLenum sourceFormat = gl::GetFormatTypeInfo(unsizedFormat, sourcePixelsType).internalFormat;
 
     DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(sourceFormat);
     ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN);
@@ -236,8 +236,7 @@
 
 ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const
 {
-    GLenum componentType = gl::GetComponentType(internalFormat);
-
+    GLenum componentType = gl::GetInternalFormatInfo(internalFormat).componentType;
     if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED)
     {
         componentType = GL_FLOAT;
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
index 466a95a..bf471f2 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -2602,8 +2602,10 @@
 {
     ASSERT(getRendererExtensions().pixelBufferObject);
 
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+
     // sRGB formats do not work with D3D11 buffer SRVs
-    if (gl::GetColorEncoding(internalFormat) == GL_SRGB)
+    if (formatInfo.colorEncoding == GL_SRGB)
     {
         return false;
     }
@@ -2615,7 +2617,7 @@
     }
 
     // We skip all 3-channel formats since sometimes format support is missing
-    if (gl::GetComponentCount(internalFormat) == 3)
+    if (formatInfo.componentCount == 3)
     {
         return false;
     }
@@ -2955,25 +2957,19 @@
         inputPitch = static_cast<int>(mapping.RowPitch);
     }
 
-    GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(textureDesc.Format);
-    GLenum sourceFormat = gl::GetFormat(sourceInternalFormat);
-    GLenum sourceType = gl::GetType(sourceInternalFormat);
-
-    GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat);
-
-    if (sourceFormat == params.format && sourceType == params.type)
+    const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3d11_gl::GetInternalFormat(textureDesc.Format));
+    if (sourceFormatInfo.format == params.format && sourceFormatInfo.type == params.type)
     {
         unsigned char *dest = static_cast<unsigned char*>(pixelsOut) + params.offset;
         for (int y = 0; y < params.area.height; y++)
         {
-            memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourcePixelSize);
+            memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourceFormatInfo.pixelBytes);
         }
     }
     else
     {
-        GLenum destInternalFormat = gl::GetSizedInternalFormat(params.format, params.type);
-        GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat);
-
+        const gl::FormatType &destFormatTypeInfo = gl::GetFormatTypeInfo(params.format, params.type);
+        const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(destFormatTypeInfo.internalFormat);
         ColorCopyFunction fastCopyFunc = d3d11::GetFastCopyFunction(textureDesc.Format, params.format, params.type);
         if (fastCopyFunc)
         {
@@ -2982,8 +2978,8 @@
             {
                 for (int x = 0; x < params.area.width; x++)
                 {
-                    void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destPixelSize;
-                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
+                    void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes;
+                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourceFormatInfo.pixelBytes;
 
                     fastCopyFunc(src, dest);
                 }
@@ -2992,7 +2988,6 @@
         else
         {
             ColorReadFunction readFunc = d3d11::GetColorReadFunction(textureDesc.Format);
-            ColorWriteFunction writeFunc = gl::GetColorWriteFunction(params.format, params.type);
 
             unsigned char temp[16]; // Maximum size of any Color<T> type used.
             META_ASSERT(sizeof(temp) >= sizeof(gl::ColorF)  &&
@@ -3003,13 +2998,13 @@
             {
                 for (int x = 0; x < params.area.width; x++)
                 {
-                    void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destPixelSize;
-                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
+                    void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes;
+                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourceFormatInfo.pixelBytes;
 
                     // readFunc and writeFunc will be using the same type of color, CopyTexImage
                     // will not allow the copy otherwise.
                     readFunc(src, temp);
-                    writeFunc(temp, dest);
+                    destFormatTypeInfo.colorWriteFunction(temp, dest);
                 }
             }
         }
@@ -3108,9 +3103,8 @@
                        drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width ||
                        drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height;
 
-    bool hasDepth = gl::GetDepthBits(drawRenderTarget11->getActualFormat()) > 0;
-    bool hasStencil = gl::GetStencilBits(drawRenderTarget11->getActualFormat()) > 0;
-    bool partialDSBlit = (hasDepth && depthBlit) != (hasStencil && stencilBlit);
+    const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getActualFormat());
+    bool partialDSBlit = (actualFormatInfo.depthBits > 0 && depthBlit) != (actualFormatInfo.stencilBits > 0 && stencilBlit);
 
     if (readRenderTarget11->getActualFormat() == drawRenderTarget->getActualFormat() &&
         !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit &&
@@ -3184,7 +3178,7 @@
         }
         else
         {
-            GLenum format = gl::GetFormat(drawRenderTarget->getInternalFormat());
+            GLenum format = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()).format;
             result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize,
                                         scissor, format, filter);
         }
diff --git a/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp
index 65e0e63..21d5b97 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -356,7 +356,7 @@
             Blit11 *blitter = mRenderer->getBlitter();
 
             blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL,
-                                 gl::GetFormat(source->getInternalFormat()), GL_LINEAR);
+                                 gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR);
         }
     }
 }
diff --git a/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp
index a300c2e..506404b 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp
@@ -780,34 +780,33 @@
     return map;
 }
 
-static const SwizzleFormatInfo GetSwizzleFormatInfo(GLenum internalFormat)
+static const SwizzleFormatInfo &GetSwizzleFormatInfo(GLenum internalFormat)
 {
     // Get the maximum sized component
     unsigned int maxBits = 1;
 
-    if (gl::IsFormatCompressed(internalFormat))
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+
+    if (formatInfo.compressed)
     {
-        unsigned int compressedBitsPerBlock = gl::GetPixelBytes(internalFormat) * 8;
-        unsigned int blockSize = gl::GetCompressedBlockWidth(internalFormat) *
-                                 gl::GetCompressedBlockHeight(internalFormat);
+        unsigned int compressedBitsPerBlock = formatInfo.pixelBytes * 8;
+        unsigned int blockSize = formatInfo.compressedBlockWidth * formatInfo.compressedBlockHeight;
         maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits);
     }
     else
     {
-        maxBits = std::max(maxBits, gl::GetAlphaBits(    internalFormat));
-        maxBits = std::max(maxBits, gl::GetRedBits(      internalFormat));
-        maxBits = std::max(maxBits, gl::GetGreenBits(    internalFormat));
-        maxBits = std::max(maxBits, gl::GetBlueBits(     internalFormat));
-        maxBits = std::max(maxBits, gl::GetLuminanceBits(internalFormat));
-        maxBits = std::max(maxBits, gl::GetDepthBits(    internalFormat));
+        maxBits = std::max(maxBits, formatInfo.alphaBits);
+        maxBits = std::max(maxBits, formatInfo.redBits);
+        maxBits = std::max(maxBits, formatInfo.greenBits);
+        maxBits = std::max(maxBits, formatInfo.blueBits);
+        maxBits = std::max(maxBits, formatInfo.luminanceBits);
+        maxBits = std::max(maxBits, formatInfo.depthBits);
     }
 
     maxBits = roundUp(maxBits, 8U);
 
-    GLenum componentType = gl::GetComponentType(internalFormat);
-
     const SwizzleInfoMap &map = GetSwizzleInfoMap();
-    SwizzleInfoMap::const_iterator iter = map.find(SwizzleSizeType(maxBits, componentType));
+    SwizzleInfoMap::const_iterator iter = map.find(SwizzleSizeType(maxBits, formatInfo.componentType));
 
     if (iter != map.end())
     {
@@ -1105,7 +1104,7 @@
 
 DXGI_FORMAT GetSwizzleTexFormat(GLint internalFormat)
 {
-    if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4)
+    if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetInternalFormatInfo(internalFormat).componentCount != 4)
     {
         const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat);
         return swizzleInfo.mTexFormat;
@@ -1118,7 +1117,7 @@
 
 DXGI_FORMAT GetSwizzleSRVFormat(GLint internalFormat)
 {
-    if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4)
+    if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetInternalFormatInfo(internalFormat).componentCount != 4)
     {
         const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat);
         return swizzleInfo.mSRVFormat;
@@ -1131,7 +1130,7 @@
 
 DXGI_FORMAT GetSwizzleRTVFormat(GLint internalFormat)
 {
-    if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4)
+    if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetInternalFormatInfo(internalFormat).componentCount != 4)
     {
         const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat);
         return swizzleInfo.mRTVFormat;
diff --git a/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
index afc5628..2f1d031 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -233,7 +233,8 @@
     UINT formatSupport;
     if (SUCCEEDED(device->CheckFormatSupport(textureFormat, &formatSupport)))
     {
-        if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0)
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+        if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
         {
             textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0);
         }
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
index e237c3b..24c26f3 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
@@ -387,7 +387,8 @@
     // 3D textures are not supported by the D3D9 backend.
     ASSERT(zoffset == 0 && depth == 1);
 
-    GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, width, unpackAlignment);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+    GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment);
 
     LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat);
     ASSERT(loadFunction != NULL);
@@ -418,8 +419,9 @@
     // 3D textures are not supported by the D3D9 backend.
     ASSERT(zoffset == 0 && depth == 1);
 
-    GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, 1);
-    GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, height, 1);
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+    GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1);
+    GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
 
     ASSERT(xoffset % d3d9::GetBlockWidth(mD3DFormat) == 0);
     ASSERT(yoffset % d3d9::GetBlockHeight(mD3DFormat) == 0);
diff --git a/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp b/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp
index 0bb7694..cc2b98c 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp
@@ -57,8 +57,8 @@
 
         bool requiresInitialization = false;
 
-        if (gl::GetDepthBits(internalFormat) > 0 ||
-            gl::GetStencilBits(internalFormat) > 0)
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+        if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
         {
             result = device->CreateDepthStencilSurface(width, height, renderFormat,
                                                        gl_d3d9::GetMultisampleType(supportedSamples),
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
index 7b8a1d3..f422743 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -814,10 +814,11 @@
         // drawing is done.
         // http://code.google.com/p/angleproject/issues/detail?id=169
 
-        DWORD colorMask = gl_d3d9::ConvertColorMask(gl::GetRedBits(internalFormat)   > 0 && blendState.colorMaskRed,
-                                                    gl::GetGreenBits(internalFormat) > 0 && blendState.colorMaskGreen,
-                                                    gl::GetBlueBits(internalFormat)  > 0 && blendState.colorMaskBlue,
-                                                    gl::GetAlphaBits(internalFormat) > 0 && blendState.colorMaskAlpha);
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+        DWORD colorMask = gl_d3d9::ConvertColorMask(formatInfo.redBits   > 0 && blendState.colorMaskRed,
+                                                    formatInfo.greenBits > 0 && blendState.colorMaskGreen,
+                                                    formatInfo.blueBits  > 0 && blendState.colorMaskBlue,
+                                                    formatInfo.alphaBits > 0 && blendState.colorMaskAlpha);
         if (colorMask == 0 && !zeroColorMaskAllowed)
         {
             // Enable green channel, but set blending so nothing will be drawn.
@@ -1745,7 +1746,7 @@
     unsigned int stencilUnmasked = 0x0;
     if (clearParams.clearStencil && frameBuffer->hasStencil())
     {
-        unsigned int stencilSize = gl::GetStencilBits(frameBuffer->getStencilbuffer()->getActualFormat());
+        unsigned int stencilSize = gl::GetInternalFormatInfo((frameBuffer->getStencilbuffer()->getActualFormat())).stencilBits;
         stencilUnmasked = (0x1 << stencilSize) - 1;
     }
 
@@ -1756,29 +1757,19 @@
     D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0);
     if (clearColor)
     {
-        gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer();
-        GLenum internalFormat = attachment->getInternalFormat();
-        GLenum actualFormat = attachment->getActualFormat();
+        const gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer();
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat());
+        const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat());
 
-        GLuint internalRedBits = gl::GetRedBits(internalFormat);
-        GLuint internalGreenBits = gl::GetGreenBits(internalFormat);
-        GLuint internalBlueBits = gl::GetBlueBits(internalFormat);
-        GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat);
+        color = D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && actualFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
+                              gl::unorm<8>((formatInfo.redBits   == 0 && actualFormatInfo.redBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
+                              gl::unorm<8>((formatInfo.greenBits == 0 && actualFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
+                              gl::unorm<8>((formatInfo.blueBits  == 0 && actualFormatInfo.blueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue));
 
-        GLuint actualRedBits = gl::GetRedBits(actualFormat);
-        GLuint actualGreenBits = gl::GetGreenBits(actualFormat);
-        GLuint actualBlueBits = gl::GetBlueBits(actualFormat);
-        GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat);
-
-        color = D3DCOLOR_ARGB(gl::unorm<8>((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
-                              gl::unorm<8>((internalRedBits   == 0 && actualRedBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
-                              gl::unorm<8>((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
-                              gl::unorm<8>((internalBlueBits  == 0 && actualBlueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue));
-
-        if ((internalRedBits   > 0 && !clearParams.colorMaskRed) ||
-            (internalGreenBits > 0 && !clearParams.colorMaskGreen) ||
-            (internalBlueBits  > 0 && !clearParams.colorMaskBlue) ||
-            (internalAlphaBits > 0 && !clearParams.colorMaskAlpha))
+        if ((formatInfo.redBits   > 0 && !clearParams.colorMaskRed) ||
+            (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
+            (formatInfo.blueBits  > 0 && !clearParams.colorMaskBlue) ||
+            (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
         {
             needMaskedColorClear = true;
         }
@@ -2772,27 +2763,20 @@
         inputPitch = lock.Pitch;
     }
 
-    GLenum sourceInternalFormat = d3d9_gl::GetInternalFormat(desc.Format);
-    GLenum sourceFormat = gl::GetFormat(sourceInternalFormat);
-    GLenum sourceType = gl::GetType(sourceInternalFormat);
-
-    GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat);
-
-    if (sourceFormat == format && sourceType == type)
+    const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3d9_gl::GetInternalFormat(desc.Format));
+    if (sourceFormatInfo.format == format && sourceFormatInfo.type == type)
     {
         // Direct copy possible
         unsigned char *dest = static_cast<unsigned char*>(pixels);
         for (int y = 0; y < rect.bottom - rect.top; y++)
         {
-            memcpy(dest + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourcePixelSize);
+            memcpy(dest + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes);
         }
     }
     else
     {
-        GLenum destInternalFormat = gl::GetSizedInternalFormat(format, type);
-        GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat);
-        GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat);
-
+        const gl::FormatType &destFormatTypeInfo = gl::GetFormatTypeInfo(format, type);
+        const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(destFormatTypeInfo.internalFormat);
         ColorCopyFunction fastCopyFunc = d3d9::GetFastCopyFunction(desc.Format, format, type);
         if (fastCopyFunc)
         {
@@ -2801,8 +2785,8 @@
             {
                 for (int x = 0; x < rect.right - rect.left; x++)
                 {
-                    void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
-                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
+                    void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destFormatInfo.pixelBytes;
+                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourceFormatInfo.pixelBytes;
 
                     fastCopyFunc(src, dest);
                 }
@@ -2811,21 +2795,19 @@
         else
         {
             ColorReadFunction readFunc = d3d9::GetColorReadFunction(desc.Format);
-            ColorWriteFunction writeFunc = gl::GetColorWriteFunction(format, type);
 
             gl::ColorF temp;
-
             for (int y = 0; y < rect.bottom - rect.top; y++)
             {
                 for (int x = 0; x < rect.right - rect.left; x++)
                 {
-                    void *dest = reinterpret_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
-                    void *src = source + y * inputPitch + x * sourcePixelSize;
+                    void *dest = reinterpret_cast<unsigned char*>(pixels) + y * outputPitch + x * destFormatInfo.pixelBytes;
+                    void *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes;
 
                     // readFunc and writeFunc will be using the same type of color, CopyTexImage
                     // will not allow the copy otherwise.
                     readFunc(src, &temp);
-                    writeFunc(&temp, dest);
+                    destFormatTypeInfo.colorWriteFunction(&temp, dest);
                 }
             }
         }
diff --git a/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp b/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp
index b065ee8..8610a45 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp
@@ -43,8 +43,8 @@
 {
     DWORD d3dusage = 0;
 
-    if (gl::GetDepthBits(internalformat) > 0 ||
-        gl::GetStencilBits(internalformat) > 0)
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+    if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
     {
         d3dusage |= D3DUSAGE_DEPTHSTENCIL;
     }
diff --git a/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp b/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp
index e605cba..7cb840a 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp
@@ -811,7 +811,7 @@
 bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format)
 {
     GLenum internalFormat = d3d9_gl::GetInternalFormat(d3dformat);
-    GLenum convertedFormat = gl::GetFormat(internalFormat);
+    GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format;
     return convertedFormat == format;
 }
 
diff --git a/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp b/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp
index 5e2db1f..358d387 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp
@@ -257,7 +257,8 @@
     gl::TextureCaps textureCaps;
 
     D3DFORMAT renderFormat = gl_d3d9::GetRenderFormat(internalFormat);
-    if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0)
+    gl::InternalFormat formatInfo = gl::GetInternalFormatInfo(internalFormat);
+    if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
     {
         textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, renderFormat));
         textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, renderFormat));
diff --git a/src/libGLESv2/validationES.cpp b/src/libGLESv2/validationES.cpp
index e963098..d608ee6 100644
--- a/src/libGLESv2/validationES.cpp
+++ b/src/libGLESv2/validationES.cpp
@@ -192,15 +192,14 @@
 
 bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
 {
-    if (!IsFormatCompressed(internalFormat))
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+    if (!formatInfo.compressed)
     {
         return false;
     }
 
-    GLint blockWidth = GetCompressedBlockWidth(internalFormat);
-    GLint blockHeight = GetCompressedBlockHeight(internalFormat);
-    if (width  < 0 || (width  > blockWidth  && width  % blockWidth  != 0) ||
-        height < 0 || (height > blockHeight && height % blockHeight != 0))
+    if (width  < 0 || (static_cast<GLuint>(width)  > formatInfo.compressedBlockWidth  && width  % formatInfo.compressedBlockWidth != 0) ||
+        height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
     {
         return false;
     }
@@ -298,7 +297,8 @@
         return gl::error(GL_INVALID_VALUE, false);
     }
 
-    if (!gl::IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion()))
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+    if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
     {
         return gl::error(GL_INVALID_ENUM, false);
     }
@@ -307,13 +307,12 @@
     // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
     // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
     // internal format must be sized and not an integer format if samples is greater than zero.
-    if (!gl::IsSizedInternalFormat(internalformat))
+    if (formatInfo.pixelBytes == 0)
     {
         return gl::error(GL_INVALID_ENUM, false);
     }
 
-    GLenum componentType = gl::GetComponentType(internalformat);
-    if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
+    if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
     {
         return gl::error(GL_INVALID_OPERATION, false);
     }
@@ -500,31 +499,31 @@
         if (readColorBuffer && drawColorBuffer)
         {
             GLenum readInternalFormat = readColorBuffer->getActualFormat();
-            GLenum readComponentType = gl::GetComponentType(readInternalFormat);
+            const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
 
             for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
             {
                 if (drawFramebuffer->isEnabledColorAttachment(i))
                 {
                     GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
-                    GLenum drawComponentType = gl::GetComponentType(drawInternalFormat);
+                    const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
 
                     // The GL ES 3.0.2 spec (pg 193) states that:
                     // 1) If the read buffer is fixed point format, the draw buffer must be as well
                     // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
                     // 3) If the read buffer is a signed integer format, the draw buffer must be as well
-                    if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
-                        !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
+                    if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
+                        !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
                     {
                         return gl::error(GL_INVALID_OPERATION, false);
                     }
 
-                    if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
+                    if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
                     {
                         return gl::error(GL_INVALID_OPERATION, false);
                     }
 
-                    if (readComponentType == GL_INT && drawComponentType != GL_INT)
+                    if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
                     {
                         return gl::error(GL_INVALID_OPERATION, false);
                     }
@@ -536,7 +535,7 @@
                 }
             }
 
-            if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
+            if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
             {
                 return gl::error(GL_INVALID_OPERATION, false);
             }
@@ -884,10 +883,10 @@
         return gl::error(GL_INVALID_OPERATION, false);
     }
 
-    GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
-                                                               : GetSizedInternalFormat(format, type);
+    GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
+    const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
 
-    GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, width, context->getState().getPackAlignment());
+    GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
     // sized query sanity check
     if (bufSize)
     {
@@ -1168,8 +1167,6 @@
 
     gl::Texture *texture = NULL;
     GLenum textureInternalFormat = GL_NONE;
-    bool textureCompressed = false;
-    bool textureIsDepth = false;
     GLint textureLevelWidth = 0;
     GLint textureLevelHeight = 0;
     GLint textureLevelDepth = 0;
@@ -1183,8 +1180,6 @@
             if (texture2d)
             {
                 textureInternalFormat = texture2d->getInternalFormat(level);
-                textureCompressed = texture2d->isCompressed(level);
-                textureIsDepth = texture2d->isDepth(level);
                 textureLevelWidth = texture2d->getWidth(level);
                 textureLevelHeight = texture2d->getHeight(level);
                 textureLevelDepth = 1;
@@ -1205,8 +1200,6 @@
             if (textureCube)
             {
                 textureInternalFormat = textureCube->getInternalFormat(target, level);
-                textureCompressed = textureCube->isCompressed(target, level);
-                textureIsDepth = false;
                 textureLevelWidth = textureCube->getWidth(target, level);
                 textureLevelHeight = textureCube->getHeight(target, level);
                 textureLevelDepth = 1;
@@ -1222,8 +1215,6 @@
             if (texture2dArray)
             {
                 textureInternalFormat = texture2dArray->getInternalFormat(level);
-                textureCompressed = texture2dArray->isCompressed(level);
-                textureIsDepth = texture2dArray->isDepth(level);
                 textureLevelWidth = texture2dArray->getWidth(level);
                 textureLevelHeight = texture2dArray->getHeight(level);
                 textureLevelDepth = texture2dArray->getLayers(level);
@@ -1239,8 +1230,6 @@
             if (texture3d)
             {
                 textureInternalFormat = texture3d->getInternalFormat(level);
-                textureCompressed = texture3d->isCompressed(level);
-                textureIsDepth = texture3d->isDepth(level);
                 textureLevelWidth = texture3d->getWidth(level);
                 textureLevelHeight = texture3d->getHeight(level);
                 textureLevelDepth = texture3d->getDepth(level);
@@ -1264,18 +1253,17 @@
         return gl::error(GL_INVALID_OPERATION, false);
     }
 
-    if (textureIsDepth)
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+
+    if (formatInfo.depthBits > 0)
     {
         return gl::error(GL_INVALID_OPERATION, false);
     }
 
-    if (textureCompressed)
+    if (formatInfo.compressed)
     {
-        GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat);
-        GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat);
-
-        if (((width % blockWidth) != 0 && width != textureLevelWidth) ||
-            ((height % blockHeight) != 0 && height != textureLevelHeight))
+        if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
+            ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
         {
             return gl::error(GL_INVALID_OPERATION, false);
         }
@@ -1297,7 +1285,7 @@
             return gl::error(GL_INVALID_VALUE, false);
         }
 
-        if (!IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion()))
+        if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
         {
             return gl::error(GL_INVALID_ENUM, false);
         }
diff --git a/src/libGLESv2/validationES2.cpp b/src/libGLESv2/validationES2.cpp
index 1a09400..59067f5 100644
--- a/src/libGLESv2/validationES2.cpp
+++ b/src/libGLESv2/validationES2.cpp
@@ -39,8 +39,7 @@
 
     if (format != GL_NONE)
     {
-        GLenum internalformat = gl::GetSizedInternalFormat(format, type);
-        if (internalformat != texture->getInternalFormat(level))
+        if (gl::GetFormatTypeInfo(format, type).internalFormat != texture->getInternalFormat(level))
         {
             return gl::error(GL_INVALID_OPERATION, false);
         }
@@ -80,8 +79,7 @@
 
     if (format != GL_NONE)
     {
-        GLenum internalformat = gl::GetSizedInternalFormat(format, type);
-        if (internalformat != texture->getInternalFormat(target, level))
+        if (gl::GetFormatTypeInfo(format, type).internalFormat != texture->getInternalFormat(target, level))
         {
             return gl::error(GL_INVALID_OPERATION, false);
         }
@@ -475,7 +473,7 @@
 
     gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
     GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
-    GLenum textureFormat = gl::GetFormat(textureInternalFormat);
+    GLenum textureFormat = gl::GetInternalFormatInfo(textureInternalFormat).format;
 
     // [OpenGL ES 2.0.24] table 3.9
     if (isSubImage)
@@ -706,10 +704,8 @@
         return gl::error(GL_INVALID_OPERATION, false);
     }
 
-    GLenum format = gl::GetFormat(internalformat);
-    GLenum type = gl::GetType(internalformat);
-
-    if (format == GL_NONE || type == GL_NONE)
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+    if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE)
     {
         return gl::error(GL_INVALID_ENUM, false);
     }
diff --git a/src/libGLESv2/validationES3.cpp b/src/libGLESv2/validationES3.cpp
index a584a71..6c71003 100644
--- a/src/libGLESv2/validationES3.cpp
+++ b/src/libGLESv2/validationES3.cpp
@@ -22,6 +22,253 @@
 namespace gl
 {
 
+// ES3 has a specific set of permutations of internal formats, formats and types which are acceptable.
+struct ES3FormatCombination
+{
+    GLenum internalFormat;
+    GLenum format;
+    GLenum type;
+};
+
+bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b)
+{
+    return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0;
+}
+
+typedef std::set<ES3FormatCombination> ES3FormatCombinationSet;
+
+static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type)
+{
+    ES3FormatCombination info;
+    info.internalFormat = internalFormat;
+    info.format = format;
+    info.type = type;
+    set->insert(info);
+}
+
+ES3FormatCombinationSet BuildES3FormatSet()
+{
+    ES3FormatCombinationSet set;
+
+    // Format combinations from ES 3.0.1 spec, table 3.2
+
+    //                        | Internal format      | Format            | Type                            |
+    //                        |                      |                   |                                 |
+    InsertES3FormatCombo(&set, GL_RGBA8,              GL_RGBA,            GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGB5_A1,            GL_RGBA,            GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGBA4,              GL_RGBA,            GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8,       GL_RGBA,            GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGBA8_SNORM,        GL_RGBA,            GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_RGBA4,              GL_RGBA,            GL_UNSIGNED_SHORT_4_4_4_4        );
+    InsertES3FormatCombo(&set, GL_RGB10_A2,           GL_RGBA,            GL_UNSIGNED_INT_2_10_10_10_REV   );
+    InsertES3FormatCombo(&set, GL_RGB5_A1,            GL_RGBA,            GL_UNSIGNED_INT_2_10_10_10_REV   );
+    InsertES3FormatCombo(&set, GL_RGB5_A1,            GL_RGBA,            GL_UNSIGNED_SHORT_5_5_5_1        );
+    InsertES3FormatCombo(&set, GL_RGBA16F,            GL_RGBA,            GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_RGBA16F,            GL_RGBA,            GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_RGBA32F,            GL_RGBA,            GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RGBA16F,            GL_RGBA,            GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RGBA8UI,            GL_RGBA_INTEGER,    GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGBA8I,             GL_RGBA_INTEGER,    GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_RGBA16UI,           GL_RGBA_INTEGER,    GL_UNSIGNED_SHORT                );
+    InsertES3FormatCombo(&set, GL_RGBA16I,            GL_RGBA_INTEGER,    GL_SHORT                         );
+    InsertES3FormatCombo(&set, GL_RGBA32UI,           GL_RGBA_INTEGER,    GL_UNSIGNED_INT                  );
+    InsertES3FormatCombo(&set, GL_RGBA32I,            GL_RGBA_INTEGER,    GL_INT                           );
+    InsertES3FormatCombo(&set, GL_RGB10_A2UI,         GL_RGBA_INTEGER,    GL_UNSIGNED_INT_2_10_10_10_REV   );
+    InsertES3FormatCombo(&set, GL_RGB8,               GL_RGB,             GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGB565,             GL_RGB,             GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_SRGB8,              GL_RGB,             GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGB8_SNORM,         GL_RGB,             GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_RGB565,             GL_RGB,             GL_UNSIGNED_SHORT_5_6_5          );
+    InsertES3FormatCombo(&set, GL_R11F_G11F_B10F,     GL_RGB,             GL_UNSIGNED_INT_10F_11F_11F_REV  );
+    InsertES3FormatCombo(&set, GL_RGB9_E5,            GL_RGB,             GL_UNSIGNED_INT_5_9_9_9_REV      );
+    InsertES3FormatCombo(&set, GL_RGB16F,             GL_RGB,             GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_RGB16F,             GL_RGB,             GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_R11F_G11F_B10F,     GL_RGB,             GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_R11F_G11F_B10F,     GL_RGB,             GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_RGB9_E5,            GL_RGB,             GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_RGB9_E5,            GL_RGB,             GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_RGB32F,             GL_RGB,             GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RGB16F,             GL_RGB,             GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_R11F_G11F_B10F,     GL_RGB,             GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RGB9_E5,            GL_RGB,             GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RGB8UI,             GL_RGB_INTEGER,     GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGB8I,              GL_RGB_INTEGER,     GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_RGB16UI,            GL_RGB_INTEGER,     GL_UNSIGNED_SHORT                );
+    InsertES3FormatCombo(&set, GL_RGB16I,             GL_RGB_INTEGER,     GL_SHORT                         );
+    InsertES3FormatCombo(&set, GL_RGB32UI,            GL_RGB_INTEGER,     GL_UNSIGNED_INT                  );
+    InsertES3FormatCombo(&set, GL_RGB32I,             GL_RGB_INTEGER,     GL_INT                           );
+    InsertES3FormatCombo(&set, GL_RG8,                GL_RG,              GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RG8_SNORM,          GL_RG,              GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_RG16F,              GL_RG,              GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_RG16F,              GL_RG,              GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_RG32F,              GL_RG,              GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RG16F,              GL_RG,              GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RG8UI,              GL_RG_INTEGER,      GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RG8I,               GL_RG_INTEGER,      GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_RG16UI,             GL_RG_INTEGER,      GL_UNSIGNED_SHORT                );
+    InsertES3FormatCombo(&set, GL_RG16I,              GL_RG_INTEGER,      GL_SHORT                         );
+    InsertES3FormatCombo(&set, GL_RG32UI,             GL_RG_INTEGER,      GL_UNSIGNED_INT                  );
+    InsertES3FormatCombo(&set, GL_RG32I,              GL_RG_INTEGER,      GL_INT                           );
+    InsertES3FormatCombo(&set, GL_R8,                 GL_RED,             GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_R8_SNORM,           GL_RED,             GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_R16F,               GL_RED,             GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_R16F,               GL_RED,             GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_R32F,               GL_RED,             GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_R16F,               GL_RED,             GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_R8UI,               GL_RED_INTEGER,     GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_R8I,                GL_RED_INTEGER,     GL_BYTE                          );
+    InsertES3FormatCombo(&set, GL_R16UI,              GL_RED_INTEGER,     GL_UNSIGNED_SHORT                );
+    InsertES3FormatCombo(&set, GL_R16I,               GL_RED_INTEGER,     GL_SHORT                         );
+    InsertES3FormatCombo(&set, GL_R32UI,              GL_RED_INTEGER,     GL_UNSIGNED_INT                  );
+    InsertES3FormatCombo(&set, GL_R32I,               GL_RED_INTEGER,     GL_INT                           );
+
+    // Unsized formats
+    InsertES3FormatCombo(&set, GL_RGBA,               GL_RGBA,            GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGBA,               GL_RGBA,            GL_UNSIGNED_SHORT_4_4_4_4        );
+    InsertES3FormatCombo(&set, GL_RGBA,               GL_RGBA,            GL_UNSIGNED_SHORT_5_5_5_1        );
+    InsertES3FormatCombo(&set, GL_RGB,                GL_RGB,             GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_RGB,                GL_RGB,             GL_UNSIGNED_SHORT_5_6_5          );
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_LUMINANCE,          GL_LUMINANCE,       GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_ALPHA,              GL_ALPHA,           GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT,     GL_SRGB_ALPHA_EXT,  GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_SRGB_EXT,           GL_SRGB_EXT,        GL_UNSIGNED_BYTE                 );
+
+    // Depth stencil formats
+    InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16,  GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT                );
+    InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24,  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT                  );
+    InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16,  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT                  );
+    InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8,   GL_DEPTH_STENCIL,   GL_UNSIGNED_INT_24_8             );
+    InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8,  GL_DEPTH_STENCIL,   GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
+
+    // From GL_EXT_sRGB
+    InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT,   GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE                  );
+    InsertES3FormatCombo(&set, GL_SRGB8,              GL_SRGB_EXT,       GL_UNSIGNED_BYTE                  );
+
+    // From GL_OES_texture_float
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_LUMINANCE,          GL_LUMINANCE,       GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_ALPHA,              GL_ALPHA,           GL_FLOAT                         );
+
+    // From GL_OES_texture_half_float
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_LUMINANCE,          GL_LUMINANCE,       GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_LUMINANCE,          GL_LUMINANCE,       GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_ALPHA,              GL_ALPHA,           GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_ALPHA,              GL_ALPHA,           GL_HALF_FLOAT_OES                );
+
+    // From GL_EXT_texture_format_BGRA8888
+    InsertES3FormatCombo(&set, GL_BGRA_EXT,           GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 );
+
+    // From GL_EXT_texture_storage
+    //                    | Internal format          | Format            | Type                            |
+    //                    |                          |                   |                                 |
+    InsertES3FormatCombo(&set, GL_ALPHA8_EXT,             GL_ALPHA,           GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT,         GL_LUMINANCE,       GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT,  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_ALPHA32F_EXT,           GL_ALPHA,           GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT,       GL_LUMINANCE,       GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_ALPHA16F_EXT,           GL_ALPHA,           GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_ALPHA16F_EXT,           GL_ALPHA,           GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT,       GL_LUMINANCE,       GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT,       GL_LUMINANCE,       GL_HALF_FLOAT_OES                );
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT                    );
+    InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES                );
+
+    // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888
+    InsertES3FormatCombo(&set, GL_BGRA8_EXT,              GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX,           GL_BGRA_EXT,        GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT);
+    InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX,           GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 );
+    InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX,         GL_BGRA_EXT,        GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT);
+    InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX,         GL_BGRA_EXT,        GL_UNSIGNED_BYTE                 );
+
+    // From GL_ANGLE_depth_texture
+    InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES,  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES         );
+
+    // Compressed formats
+    // From ES 3.0.1 spec, table 3.16
+    //                    | Internal format                             | Format                                      | Type           |
+    //                    |                                             |                                             |                |
+    InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC,                        GL_COMPRESSED_R11_EAC,                        GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC,                        GL_COMPRESSED_R11_EAC,                        GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC,                 GL_COMPRESSED_SIGNED_R11_EAC,                 GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC,                       GL_COMPRESSED_RG11_EAC,                       GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC,                GL_COMPRESSED_SIGNED_RG11_EAC,                GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2,                      GL_COMPRESSED_RGB8_ETC2,                      GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2,                     GL_COMPRESSED_SRGB8_ETC2,                     GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_UNSIGNED_BYTE);
+
+
+    // From GL_EXT_texture_compression_dxt1
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,              GL_COMPRESSED_RGB_S3TC_DXT1_EXT,              GL_UNSIGNED_BYTE);
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,             GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,             GL_UNSIGNED_BYTE);
+
+    // From GL_ANGLE_texture_compression_dxt3
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,           GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,           GL_UNSIGNED_BYTE);
+
+    // From GL_ANGLE_texture_compression_dxt5
+    InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,           GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,           GL_UNSIGNED_BYTE);
+
+    return set;
+}
+
+static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
+{
+    // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
+    // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+    if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    // The type and format are valid if any supported internal format has that type and format
+    bool formatSupported = false;
+    bool typeSupported = false;
+
+    static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet();
+    for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++)
+    {
+        if (i->format == format || i->type == type)
+        {
+            const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat);
+            bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions());
+            if (supported && formatInfo.type == type)
+            {
+                typeSupported = true;
+            }
+            if (supported && formatInfo.format == format)
+            {
+                formatSupported = true;
+            }
+        }
+    }
+
+    if (!typeSupported || !formatSupported)
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    // Check if this is a valid format combination to load texture data
+    ES3FormatCombination searchFormat;
+    searchFormat.internalFormat = internalFormat;
+    searchFormat.format = format;
+    searchFormat.type = type;
+
+    if (es3FormatSet.find(searchFormat) == es3FormatSet.end())
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    return true;
+}
+
 bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
                                    GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                    GLint border, GLenum format, GLenum type, const GLvoid *pixels)
@@ -172,6 +419,7 @@
 
     // Validate texture formats
     GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
+    const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat);
     if (isCompressed)
     {
         if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
@@ -179,7 +427,7 @@
             return gl::error(GL_INVALID_OPERATION, false);
         }
 
-        if (!gl::IsFormatCompressed(actualInternalFormat))
+        if (!actualFormatInfo.compressed)
         {
             return gl::error(GL_INVALID_ENUM, false);
         }
@@ -191,18 +439,9 @@
     }
     else
     {
-        // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
-        // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
-        if (!gl::IsValidInternalFormat(actualInternalFormat, context->getExtensions(), context->getClientVersion()) ||
-            !gl::IsValidFormat(format, context->getExtensions(), context->getClientVersion()) ||
-            !gl::IsValidType(type, context->getExtensions(), context->getClientVersion()))
+        if (!ValidateTexImageFormatCombination(context, internalformat, format, type))
         {
-            return gl::error(GL_INVALID_ENUM, false);
-        }
-
-        if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getExtensions(), context->getClientVersion()))
-        {
-            return gl::error(GL_INVALID_OPERATION, false);
+            return false;
         }
 
         if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
@@ -262,10 +501,9 @@
         size_t widthSize = static_cast<size_t>(width);
         size_t heightSize = static_cast<size_t>(height);
         size_t depthSize = static_cast<size_t>(depth);
-        GLenum sizedFormat = gl::IsSizedInternalFormat(actualInternalFormat) ? actualInternalFormat
-                                                                             : gl::GetSizedInternalFormat(actualInternalFormat, type);
+        GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type);
 
-        size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(sizedFormat));
+        size_t pixelBytes = static_cast<size_t>(gl::GetInternalFormatInfo(sizedFormat).pixelBytes);
 
         if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
             !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
@@ -287,7 +525,7 @@
 
         // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
         // indicated by type.
-        size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type));
+        size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeInfo(type).bytes);
 
         if ((offset % dataBytesPerPixel) != 0)
         {
@@ -304,6 +542,290 @@
     return true;
 }
 
+struct EffectiveInternalFormatInfo
+{
+    GLenum mEffectiveFormat;
+    GLenum mDestFormat;
+    GLuint mMinRedBits;
+    GLuint mMaxRedBits;
+    GLuint mMinGreenBits;
+    GLuint mMaxGreenBits;
+    GLuint mMinBlueBits;
+    GLuint mMaxBlueBits;
+    GLuint mMinAlphaBits;
+    GLuint mMaxAlphaBits;
+
+    EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits,
+                                GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits,
+                                GLuint minAlphaBits, GLuint maxAlphaBits)
+        : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits),
+          mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits),
+          mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits),
+          mMaxAlphaBits(maxAlphaBits) {};
+};
+
+typedef std::vector<EffectiveInternalFormatInfo> EffectiveInternalFormatList;
+
+static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList()
+{
+    EffectiveInternalFormatList list;
+
+    // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
+    //                                                    linear source buffer component sizes.
+    //                                                                            | Source channel min/max sizes |
+    //                                         Effective Internal Format |  N/A   |  R   |  G   |  B   |  A      |
+    list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT,              GL_NONE, 0,  0, 0,  0, 0,  0, 1, 8));
+    list.push_back(EffectiveInternalFormatInfo(GL_R8,                      GL_NONE, 1,  8, 0,  0, 0,  0, 0, 0));
+    list.push_back(EffectiveInternalFormatInfo(GL_RG8,                     GL_NONE, 1,  8, 1,  8, 0,  0, 0, 0));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB565,                  GL_NONE, 1,  5, 1,  6, 1,  5, 0, 0));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB8,                    GL_NONE, 6,  8, 7,  8, 6,  8, 0, 0));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGBA4,                   GL_NONE, 1,  4, 1,  4, 1,  4, 1, 4));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1,                 GL_NONE, 5,  5, 5,  5, 5,  5, 1, 1));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGBA8,                   GL_NONE, 5,  8, 5,  8, 5,  8, 2, 8));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2,                GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2));
+
+    return list;
+}
+
+static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList()
+{
+    EffectiveInternalFormatList list;
+
+    // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and
+    //                                                    linear source buffer component sizes.
+    //                                                                                        |          Source channel min/max sizes            |
+    //                                         Effective Internal Format |    Dest Format     |     R     |      G     |      B     |      A     |
+    list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT,              GL_ALPHA,           0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1,        8));
+    list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT,          GL_LUMINANCE,       1,        8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX));
+    list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT,   GL_LUMINANCE_ALPHA, 1,        8, 0, UINT_MAX, 0, UINT_MAX, 1,        8));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB565,                  GL_RGB,             1,        5, 1,        6, 1,        5, 0, UINT_MAX));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB8,                    GL_RGB,             6,        8, 7,        8, 6,        8, 0, UINT_MAX));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGBA4,                   GL_RGBA,            1,        4, 1,        4, 1,        4, 1,        4));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1,                 GL_RGBA,            5,        5, 5,        5, 5,        5, 1,        1));
+    list.push_back(EffectiveInternalFormatInfo(GL_RGBA8,                   GL_RGBA,            5,        8, 5,        8, 5,        8, 5,        8));
+
+    return list;
+}
+
+static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat,
+                                       GLenum *outEffectiveFormat)
+{
+    const EffectiveInternalFormatList *list = NULL;
+    GLenum targetFormat = GL_NONE;
+
+    if (destFormat.pixelBytes > 0)
+    {
+        static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList();
+        list = &sizedList;
+    }
+    else
+    {
+        static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList();
+        list = &unsizedList;
+        targetFormat = destFormat.format;
+    }
+
+    for (size_t curFormat = 0; curFormat < list->size(); ++curFormat)
+    {
+        const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat);
+        if ((formatInfo.mDestFormat == targetFormat) &&
+            (formatInfo.mMinRedBits   <= srcFormat.redBits   && formatInfo.mMaxRedBits   >= srcFormat.redBits)   &&
+            (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) &&
+            (formatInfo.mMinBlueBits  <= srcFormat.blueBits  && formatInfo.mMaxBlueBits  >= srcFormat.blueBits)  &&
+            (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits))
+        {
+            *outEffectiveFormat = formatInfo.mEffectiveFormat;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+struct CopyConversion
+{
+    GLenum mTextureFormat;
+    GLenum mFramebufferFormat;
+
+    CopyConversion(GLenum textureFormat, GLenum framebufferFormat)
+        : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { }
+
+    bool operator<(const CopyConversion& other) const
+    {
+        return memcmp(this, &other, sizeof(CopyConversion)) < 0;
+    }
+};
+
+typedef std::set<CopyConversion> CopyConversionSet;
+
+static CopyConversionSet BuildValidES3CopyTexImageCombinations()
+{
+    CopyConversionSet set;
+
+    // From ES 3.0.1 spec, table 3.15
+    set.insert(CopyConversion(GL_ALPHA, GL_RGBA));
+    set.insert(CopyConversion(GL_LUMINANCE, GL_RED));
+    set.insert(CopyConversion(GL_LUMINANCE, GL_RG));
+    set.insert(CopyConversion(GL_LUMINANCE, GL_RGB));
+    set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA));
+    set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA));
+    set.insert(CopyConversion(GL_RED, GL_RED));
+    set.insert(CopyConversion(GL_RED, GL_RG));
+    set.insert(CopyConversion(GL_RED, GL_RGB));
+    set.insert(CopyConversion(GL_RED, GL_RGBA));
+    set.insert(CopyConversion(GL_RG, GL_RG));
+    set.insert(CopyConversion(GL_RG, GL_RGB));
+    set.insert(CopyConversion(GL_RG, GL_RGBA));
+    set.insert(CopyConversion(GL_RGB, GL_RGB));
+    set.insert(CopyConversion(GL_RGB, GL_RGBA));
+    set.insert(CopyConversion(GL_RGBA, GL_RGBA));
+
+    // Necessary for ANGLE back-buffers
+    set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT));
+    set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT));
+    set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT));
+    set.insert(CopyConversion(GL_RED, GL_BGRA_EXT));
+    set.insert(CopyConversion(GL_RG, GL_BGRA_EXT));
+    set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT));
+    set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT));
+
+    set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER));
+    set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER));
+    set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER));
+    set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER));
+    set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER));
+    set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER));
+    set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER));
+    set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER));
+    set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER));
+    set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER));
+
+    return set;
+}
+
+static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle)
+{
+    const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat);
+    const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat);
+
+    static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations();
+    if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end())
+    {
+        // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats
+        // must both be signed, unsigned, or fixed point and both source and destinations
+        // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed
+        // conversion between fixed and floating point.
+
+        if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB))
+        {
+            return false;
+        }
+
+        if (((textureInternalFormatInfo.componentType == GL_INT)          != (framebufferInternalFormatInfo.componentType == GL_INT         )) ||
+            ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT)))
+        {
+            return false;
+        }
+
+        if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
+             textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
+             textureInternalFormatInfo.componentType == GL_FLOAT) &&
+            !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
+              framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
+              framebufferInternalFormatInfo.componentType == GL_FLOAT))
+        {
+            return false;
+        }
+
+        // GLES specification 3.0.3, sec 3.8.5, pg 139-140:
+        // The effective internal format of the source buffer is determined with the following rules applied in order:
+        //    * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the
+        //      effective internal format is the source buffer's sized internal format.
+        //    * If the source buffer is a texture that was created with an unsized base internal format, then the
+        //      effective internal format is the source image array's effective internal format, as specified by table
+        //      3.12, which is determined from the <format> and <type> that were used when the source image array was
+        //      specified by TexImage*.
+        //    * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where
+        //      Destination Internal Format matches internalformat and where the [source channel sizes] are consistent
+        //      with the values of the source buffer's [channel sizes]. Table 3.17 is used if the
+        //      FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING
+        //      is SRGB.
+        const InternalFormat *sourceEffectiveFormat = NULL;
+        if (readBufferHandle != 0)
+        {
+            // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer
+            if (framebufferInternalFormatInfo.pixelBytes > 0)
+            {
+                sourceEffectiveFormat = &framebufferInternalFormatInfo;
+            }
+            else
+            {
+                // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format
+                // texture. We can use the same table we use when creating textures to get its effective sized format.
+                const FormatType &typeInfo = GetFormatTypeInfo(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type);
+                sourceEffectiveFormat = &GetInternalFormatInfo(typeInfo.internalFormat);
+            }
+        }
+        else
+        {
+            // The effective internal format must be derived from the source framebuffer's channel sizes.
+            // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17)
+            if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR)
+            {
+                GLenum effectiveFormat;
+                if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat))
+                {
+                    sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat);
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)
+            {
+                // SRGB buffers can only be copied to sized format destinations according to table 3.18
+                if ((textureInternalFormatInfo.pixelBytes > 0) &&
+                    (framebufferInternalFormatInfo.redBits   >= 1 && framebufferInternalFormatInfo.redBits   <= 8) &&
+                    (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) &&
+                    (framebufferInternalFormatInfo.blueBits  >= 1 && framebufferInternalFormatInfo.blueBits  <= 8) &&
+                    (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8))
+                {
+                    sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8);
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                UNREACHABLE();
+                return false;
+            }
+        }
+
+        if (textureInternalFormatInfo.pixelBytes > 0)
+        {
+            // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized,
+            // component sizes of the source and destination formats must exactly match
+            if (textureInternalFormatInfo.redBits   != sourceEffectiveFormat->redBits   ||
+                textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits ||
+                textureInternalFormatInfo.blueBits  != sourceEffectiveFormat->blueBits  ||
+                textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits)
+            {
+                return false;
+            }
+        }
+
+
+        return true; // A conversion function exists, and no rule in the specification has precluded conversion
+                     // between these formats.
+    }
+
+    return false;
+}
+
 bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
                                        bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
                                        GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
@@ -333,18 +855,16 @@
 
     if (isSubImage)
     {
-        if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
-                                                context->getState().getReadFramebuffer()->id(),
-                                                context->getClientVersion()))
+        if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
+                                               context->getState().getReadFramebuffer()->id()))
         {
             return gl::error(GL_INVALID_OPERATION, false);
         }
     }
     else
     {
-        if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat,
-                                                context->getState().getReadFramebuffer()->id(),
-                                                context->getClientVersion()))
+        if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
+                                                context->getState().getReadFramebuffer()->id()))
         {
             return gl::error(GL_INVALID_OPERATION, false);
         }
@@ -440,12 +960,13 @@
         return gl::error(GL_INVALID_OPERATION, false);
     }
 
-    if (!gl::IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion()))
+    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+    if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
     {
         return gl::error(GL_INVALID_ENUM, false);
     }
 
-    if (!gl::IsSizedInternalFormat(internalformat))
+    if (formatInfo.pixelBytes == 0)
     {
         return gl::error(GL_INVALID_ENUM, false);
     }
@@ -529,6 +1050,8 @@
 
 bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
 {
+    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
+
     switch (format)
     {
       case GL_RGBA:
@@ -543,7 +1066,7 @@
             }
             break;
           case GL_FLOAT:
-            if (gl::GetComponentType(internalFormat) != GL_FLOAT)
+            if (internalFormatInfo.componentType != GL_FLOAT)
             {
                 return false;
             }
@@ -556,13 +1079,13 @@
         switch (type)
         {
           case GL_INT:
-            if (gl::GetComponentType(internalFormat) != GL_INT)
+            if (internalFormatInfo.componentType != GL_INT)
             {
                 return false;
             }
             break;
           case GL_UNSIGNED_INT:
-            if (gl::GetComponentType(internalFormat) != GL_UNSIGNED_INT)
+            if (internalFormatInfo.componentType != GL_UNSIGNED_INT)
             {
                 return false;
             }