Add support for GL texture storage

Review URL: http://codereview.appspot.com/5462046/



git-svn-id: http://skia.googlecode.com/svn/trunk@2966 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrGLDefines.h b/include/gpu/GrGLDefines.h
index 6a57982..e66eec4 100644
--- a/include/gpu/GrGLDefines.h
+++ b/include/gpu/GrGLDefines.h
@@ -294,6 +294,7 @@
 #define GR_GL_LUMINANCE                      0x1909
 #define GR_GL_LUMINANCE_ALPHA                0x190A
 #define GR_GL_PALETTE8_RGBA8                 0x8B96
+#define GR_GL_ALPHA8                         0x803C
 
 /* PixelType */
 /*      GL_UNSIGNED_BYTE */
@@ -632,6 +633,7 @@
 #define GR_GL_RGB565                         0x8D62
 #define GR_GL_RGBA8                          0x8058
 #define GR_GL_RGB8                           0x8051
+#define GR_GL_BGRA8                          0x93A1
 #define GR_GL_SRGB                           0x8C40
 #define GR_GL_SRGB8                          0x8C41
 #define GR_GL_SRGB_ALPHA                     0x8C42
diff --git a/include/gpu/GrGLInterface.h b/include/gpu/GrGLInterface.h
index e0925bd..716cff9 100644
--- a/include/gpu/GrGLInterface.h
+++ b/include/gpu/GrGLInterface.h
@@ -188,6 +188,7 @@
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLStencilOpSeparateProc)(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexImage2DProc)(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexParameteriProc)(GrGLenum target, GrGLenum pname, GrGLint param);
+    typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexStorage2DProc)(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexSubImage2DProc)(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1fProc)(GrGLint location, GrGLfloat v0);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1iProc)(GrGLint location, GrGLint v0);
@@ -352,6 +353,7 @@
     GrGLTexImage2DProc fTexImage2D;
     GrGLTexParameteriProc fTexParameteri;
     GrGLTexSubImage2DProc fTexSubImage2D;
+    GrGLTexStorage2DProc fTexStorage2D;
     GrGLUniform1fProc fUniform1f;
     GrGLUniform1iProc fUniform1i;
     GrGLUniform1fvProc fUniform1fv;
diff --git a/src/gpu/GrGLCreateNullInterface.cpp b/src/gpu/GrGLCreateNullInterface.cpp
index 2b7e43b..d4a88c1 100644
--- a/src/gpu/GrGLCreateNullInterface.cpp
+++ b/src/gpu/GrGLCreateNullInterface.cpp
@@ -55,6 +55,7 @@
 GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilOpSeparate(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass) {}
 GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexImage2D(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels) {}
 GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexParameteri(GrGLenum target, GrGLenum pname, GrGLint param) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexStorage2D(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height) {}
 GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexSubImage2D(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels) {}
 GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform1f(GrGLint location, GrGLfloat v0) {}
 GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform1i(GrGLint location, GrGLint v0) {}
@@ -457,6 +458,7 @@
         interface->fTexImage2D = nullGLTexImage2D;
         interface->fTexParameteri = nullGLTexParameteri;
         interface->fTexSubImage2D = nullGLTexSubImage2D;
+        interface->fTexStorage2D = nullGLTexStorage2D;
         interface->fUniform1f = nullGLUniform1f;
         interface->fUniform1i = nullGLUniform1i;
         interface->fUniform1fv = nullGLUniform1fv;
diff --git a/src/gpu/GrGLInterface.cpp b/src/gpu/GrGLInterface.cpp
index d46aaa7..66aea63 100644
--- a/src/gpu/GrGLInterface.cpp
+++ b/src/gpu/GrGLInterface.cpp
@@ -178,6 +178,7 @@
     fStencilOpSeparate = NULL;
     fTexImage2D = NULL;
     fTexParameteri = NULL;
+    fTexStorage2D = NULL;
     fTexSubImage2D = NULL;
     fUniform1f = NULL;
     fUniform1i = NULL;
@@ -416,6 +417,14 @@
         return false;
     }
 
+    // GL_EXT_texture_storage is part of desktop 4.2
+    // There is a desktop ARB extension and an ES+desktop EXT extension
+    if ((kDesktop_GrGLBinding == fBindingsExported &&
+         (glVer >= GR_GL_VER(4,2)) ||
+          GrGLHasExtensionFromString("GL_ARB_texture_storage", ext)) ||
+        GrGLHasExtensionFromString("GL_EXT_texture_storage", ext)) {
+    }
+
     // FBO MSAA
     if (kDesktop_GrGLBinding == fBindingsExported) {
         // GL 3.0 and the ARB extension have multisample + blit
diff --git a/src/gpu/GrGLTexture.cpp b/src/gpu/GrGLTexture.cpp
index 327f7cf..0a38da3 100644
--- a/src/gpu/GrGLTexture.cpp
+++ b/src/gpu/GrGLTexture.cpp
@@ -35,7 +35,6 @@
     fTexIDObj           = new GrGLTexID(GPUGL->glInterface(),
                                         textureDesc.fTextureID,
                                         textureDesc.fOwnsID);
-    fInternalFormat     = textureDesc.fInternalFormat;
     fOrientation        = textureDesc.fOrientation;
 
     if (NULL != rtDesc) {
diff --git a/src/gpu/GrGLTexture.h b/src/gpu/GrGLTexture.h
index b023bc6..664742c 100644
--- a/src/gpu/GrGLTexture.h
+++ b/src/gpu/GrGLTexture.h
@@ -64,7 +64,6 @@
         int             fHeight;
         GrPixelConfig   fConfig;
         GrGLuint        fTextureID;
-        GrGLenum        fInternalFormat;
         bool            fOwnsID;
         Orientation     fOrientation;
     };
@@ -95,8 +94,6 @@
     }
     GrGLuint textureID() const { return fTexIDObj->id(); }
 
-    GrGLenum internalFormat() const { return fInternalFormat; }
-
     // Ganesh assumes texture coordinates have their origin
     // in the top-left corner of the image. OpenGL, however,
     // has the origin in the lower-left corner. For content that
@@ -119,7 +116,6 @@
     TexParams                       fTexParams;
     GrGpu::ResetTimestamp           fTexParamsTimestamp;
     GrGLTexID*                      fTexIDObj;
-    GrGLenum                        fInternalFormat;
     Orientation                     fOrientation;
 
     void init(GrGpuGL* gpu,
diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp
index 85defc5..d0fb12fe 100644
--- a/src/gpu/GrGpuGL.cpp
+++ b/src/gpu/GrGpuGL.cpp
@@ -339,6 +339,12 @@
     fGLCaps.fTextureUsageSupport = (kES2_GrGLBinding == this->glBinding()) &&
                                    this->hasExtension("GL_ANGLE_texture_usage");
 
+    // Tex storage is in desktop 4.2 and can be an extension to desktop or ES.
+    fGLCaps.fTexStorageSupport = (kDesktop_GrGLBinding == this->glBinding() &&
+                                  fGLVersion >= GR_GL_VER(4,2)) ||
+                                 this->hasExtension("GL_ARB_texture_storage") ||
+                                 this->hasExtension("GL_EXT_texture_storage");
+
     fCaps.fHWAALineSupport = (kDesktop_GrGLBinding == this->glBinding());
 
     ////////////////////////////////////////////////////////////////////////////
@@ -555,13 +561,11 @@
 }
 
 GrTexture* GrGpuGL::onCreatePlatformTexture(const GrPlatformTextureDesc& desc) {
-    GrGLenum dontCare;
     GrGLTexture::Desc glTexDesc;
-    if (!this->canBeTexture(desc.fConfig, &glTexDesc.fInternalFormat,
-                            &dontCare, &dontCare)) {
+    if (!configToGLFormats(desc.fConfig, false, NULL, NULL, NULL)) {
         return NULL;
     }
-    
+
     glTexDesc.fWidth = desc.fWidth;
     glTexDesc.fHeight = desc.fHeight;
     glTexDesc.fConfig = desc.fConfig;
@@ -670,9 +674,7 @@
 
     if (isTexture) {
         GrGLTexture::Desc texDesc;
-        GrGLenum dontCare;
-        if (!canBeTexture(desc.fConfig, &texDesc.fInternalFormat,
-                         &dontCare, &dontCare)) {
+        if (!this->configToGLFormats(desc.fConfig, false, NULL, NULL, NULL)) {
             return NULL;
         }
         texDesc.fWidth  = desc.fWidth;
@@ -710,11 +712,11 @@
                                    int left, int top, int width, int height,
                                    GrPixelConfig config, const void* buffer,
                                    size_t rowBytes) {
-    GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
-
     if (NULL == buffer) {
         return;
     }
+    GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
+
     this->setSpareTextureUnit();
     GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID()));
     GrGLTexture::Desc desc;
@@ -723,7 +725,6 @@
     desc.fHeight = glTex->height();
     desc.fOrientation = glTex->orientation();
     desc.fTextureID = glTex->textureID();
-    desc.fInternalFormat = glTex->internalFormat();
 
     this->uploadTexData(desc, false,
                         left, top, width, height, 
@@ -776,15 +777,33 @@
     // in case we need a temporary, trimmed copy of the src pixels
     SkAutoSMalloc<128 * 128> tempStorage;
 
-    GrGLenum dontCare;
+    bool useTexStorage = isNewTexture &&
+                         this->glCaps().fTexStorageSupport;
+    if (useTexStorage) {
+        if (kDesktop_GrGLBinding == this->glBinding()) {
+            // 565 is not a sized internal format on desktop GL. So on desktop
+            // with 565 we always use an unsized internal format to let the
+            // system pick the best sized format to convert the 565 data to.
+            // Since glTexStorage only allows sized internal formats we will
+            // instead fallback to glTexImage2D.
+            useTexStorage = desc.fConfig != kRGB_565_GrPixelConfig;
+        } else {
+            // ES doesn't allow paletted textures to be used with tex storage
+            useTexStorage = desc.fConfig != kIndex_8_GrPixelConfig;
+        }
+    }
+
+    GrGLenum internalFormat;
     GrGLenum externalFormat;
     GrGLenum externalType;
-    if (!this->canBeTexture(dataConfig, &dontCare,
-                            &externalFormat, &externalType)) {
+    // glTexStorage requires sized internal formats on both desktop and ES. ES
+    // glTexImage requires an unsized format.
+    if (!this->configToGLFormats(dataConfig, useTexStorage, &internalFormat,
+                                 &externalFormat, &externalType)) {
         return false;
     }
 
-    if (!isNewTexture && GR_GL_PALETTE8_RGBA8 == desc.fInternalFormat) {
+    if (!isNewTexture && GR_GL_PALETTE8_RGBA8 == internalFormat) {
         // paletted textures cannot be updated
         return false;
     }
@@ -798,7 +817,6 @@
     bool restoreGLRowLength = false;
     bool swFlipY = false;
     bool glFlipY = false;
-
     if (NULL != data) {
         if (GrGLTexture::kBottomUp_Orientation == desc.fOrientation) {
             if (this->glCaps().fUnpackFlipYSupport) {
@@ -846,32 +864,52 @@
         0 == left && 0 == top &&
         desc.fWidth == width && desc.fHeight == height) {
         GrGLClearErr(this->glInterface());
-        if (GR_GL_PALETTE8_RGBA8 == desc.fInternalFormat) {
-            GrGLsizei imageSize = desc.fWidth * desc.fHeight +
-                                  kGrColorTableSize;
+        if (useTexStorage) {
+            // We never resize  or change formats of textures. We don't use
+            // mipmaps currently.
             GR_GL_CALL_NOERRCHECK(this->glInterface(),
-                                  CompressedTexImage2D(GR_GL_TEXTURE_2D,
-                                                       0, // level
-                                                       desc.fInternalFormat,
-                                                       desc.fWidth,
-                                                       desc.fHeight,
-                                                       0, // border
-                                                       imageSize,
-                                                       data));
+                                  TexStorage2D(GR_GL_TEXTURE_2D,
+                                               1, // levels
+                                               internalFormat,
+                                               desc.fWidth, desc.fHeight));
         } else {
-             GR_GL_CALL_NOERRCHECK(this->glInterface(),
-                                   TexImage2D(GR_GL_TEXTURE_2D,
-                                              0, // level
-                                              desc.fInternalFormat,
-                                              desc.fWidth,
-                                              desc.fHeight,
-                                              0, // border
-                                              externalFormat,
-                                              externalType,
-                                              data));
+            if (GR_GL_PALETTE8_RGBA8 == internalFormat) {
+                GrGLsizei imageSize = desc.fWidth * desc.fHeight +
+                                      kGrColorTableSize;
+                GR_GL_CALL_NOERRCHECK(this->glInterface(),
+                                      CompressedTexImage2D(GR_GL_TEXTURE_2D,
+                                                           0, // level
+                                                           internalFormat,
+                                                           desc.fWidth,
+                                                           desc.fHeight,
+                                                           0, // border
+                                                           imageSize,
+                                                           data));
+            } else {
+                GR_GL_CALL_NOERRCHECK(this->glInterface(),
+                                      TexImage2D(GR_GL_TEXTURE_2D,
+                                                 0, // level
+                                                 internalFormat,
+                                                 desc.fWidth, desc.fHeight,
+                                                 0, // border
+                                                 externalFormat, externalType,
+                                                 data));
+            }
         }
-        if (GR_GL_GET_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
-             succeeded = false;
+        GrGLenum error = GR_GL_GET_ERROR(this->glInterface());
+        if (error != GR_GL_NO_ERROR) {
+            succeeded = false;
+        } else {
+            // if we have data and we used TexStorage to create the texture, we
+            // now upload with TexSubImage.
+            if (NULL != data && useTexStorage) {
+                GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
+                                      0, // level
+                                      left, top,
+                                      width, height,
+                                      externalFormat, externalType,
+                                      data));
+            }
         }
     } else {
         if (swFlipY || glFlipY) {
@@ -923,7 +961,10 @@
         GL_CALL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID));
         if (!desc->fRTFBOID ||
             !desc->fMSColorRenderbufferID || 
-            !this->fboInternalFormat(desc->fConfig, &msColorFormat)) {
+            !this->configToGLFormats(desc->fConfig,
+                                     // GLES requires sized internal formats
+                                     kES2_GrGLBinding == this->glBinding(),
+                                     &msColorFormat, NULL, NULL)) {
             goto FAILED;
         }
     } else {
@@ -1004,8 +1045,6 @@
 
     GrGLTexture::Desc glTexDesc;
     GrGLRenderTarget::Desc  glRTDesc;
-    GrGLenum externalFormat;
-    GrGLenum externalType;
 
     glTexDesc.fWidth  = desc.fWidth;
     glTexDesc.fHeight = desc.fHeight;
@@ -1019,12 +1058,6 @@
     glRTDesc.fConfig = glTexDesc.fConfig;
 
     bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit);
-    if (!canBeTexture(desc.fConfig,
-                      &glTexDesc.fInternalFormat,
-                      &externalFormat,
-                      &externalType)) {
-        return return_null_texture();
-    }
 
     const Caps& caps = this->getCaps();
 
@@ -1471,10 +1504,9 @@
                            void* buffer,
                            size_t rowBytes,
                            bool invertY) {
-    GrGLenum internalFormat;  // we don't use this for glReadPixels
     GrGLenum format;
     GrGLenum type;
-    if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
+    if (!this->configToGLFormats(config, false, NULL, &format, &type)) {
         return false;
     }
     size_t bpp = GrBytesPerPixel(config);
@@ -2278,15 +2310,32 @@
     }
 }
 
-bool GrGpuGL::canBeTexture(GrPixelConfig config,
-                           GrGLenum* internalFormat,
-                           GrGLenum* externalFormat,
-                           GrGLenum* externalType) {
+bool GrGpuGL::configToGLFormats(GrPixelConfig config,
+                                bool getSizedInternalFormat,
+                                GrGLenum* internalFormat,
+                                GrGLenum* externalFormat,
+                                GrGLenum* externalType) {
+    GrGLenum dontCare;
+    if (NULL == internalFormat) {
+        internalFormat = &dontCare;
+    }
+    if (NULL == externalFormat) {
+        externalFormat = &dontCare;
+    }
+    if (NULL == externalType) {
+        externalType = &dontCare;
+    }
+
     switch (config) {
         case kRGBA_8888_PM_GrPixelConfig:
         case kRGBA_8888_UPM_GrPixelConfig:
             *internalFormat = GR_GL_RGBA;
             *externalFormat = GR_GL_RGBA;
+            if (getSizedInternalFormat) {
+                *internalFormat = GR_GL_RGBA8;
+            } else {
+                *internalFormat = GR_GL_RGBA;
+            }
             *externalType = GR_GL_UNSIGNED_BYTE;
             break;
         case kBGRA_8888_PM_GrPixelConfig:
@@ -2295,9 +2344,17 @@
                 return false;
             }
             if (fGLCaps.fBGRAIsInternalFormat) {
-                *internalFormat = GR_GL_BGRA;
+                if (getSizedInternalFormat) {
+                    *internalFormat = GR_GL_BGRA8;
+                } else {
+                    *internalFormat = GR_GL_BGRA;
+                }
             } else {
-                *internalFormat = GR_GL_RGBA;
+                if (getSizedInternalFormat) {
+                    *internalFormat = GR_GL_RGBA8;
+                } else {
+                    *internalFormat = GR_GL_RGBA;
+                }
             }
             *externalFormat = GR_GL_BGRA;
             *externalType = GR_GL_UNSIGNED_BYTE;
@@ -2305,11 +2362,25 @@
         case kRGB_565_GrPixelConfig:
             *internalFormat = GR_GL_RGB;
             *externalFormat = GR_GL_RGB;
+            if (getSizedInternalFormat) {
+                if (this->glBinding() == kDesktop_GrGLBinding) {
+                    return false;
+                } else {
+                    *internalFormat = GR_GL_RGB565;
+                }
+            } else {
+                *internalFormat = GR_GL_RGB;
+            }
             *externalType = GR_GL_UNSIGNED_SHORT_5_6_5;
             break;
         case kRGBA_4444_GrPixelConfig:
             *internalFormat = GR_GL_RGBA;
             *externalFormat = GR_GL_RGBA;
+            if (getSizedInternalFormat) {
+                *internalFormat = GR_GL_RGBA4;
+            } else {
+                *internalFormat = GR_GL_RGBA;
+            }
             *externalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
             break;
         case kIndex_8_GrPixelConfig:
@@ -2317,6 +2388,9 @@
                 *internalFormat = GR_GL_PALETTE8_RGBA8;
                 // glCompressedTexImage doesn't take external params
                 *externalFormat = GR_GL_PALETTE8_RGBA8;
+                // no sized/unsized internal format distinction here
+                *internalFormat = GR_GL_PALETTE8_RGBA8;
+                // unused with CompressedTexImage
                 *externalType = GR_GL_UNSIGNED_BYTE;
             } else {
                 return false;
@@ -2325,6 +2399,11 @@
         case kAlpha_8_GrPixelConfig:
             *internalFormat = GR_GL_ALPHA;
             *externalFormat = GR_GL_ALPHA;
+            if (getSizedInternalFormat) {
+                *internalFormat = GR_GL_ALPHA8;
+            } else {
+                *internalFormat = GR_GL_ALPHA;
+            }
             *externalType = GR_GL_UNSIGNED_BYTE;
             break;
         default:
@@ -2348,51 +2427,6 @@
     }
 }
 
-/* On ES the internalFormat and format must match for TexImage and we use
-   GL_RGB, GL_RGBA for color formats. We also generally like having the driver
-   decide the internalFormat. However, on ES internalFormat for
-   RenderBufferStorage* has to be a specific format (not a base format like
-   GL_RGBA).
- */
-bool GrGpuGL::fboInternalFormat(GrPixelConfig config, GrGLenum* format) {
-    switch (config) {
-        // The ES story for BGRA and RenderbufferStorage appears murky. It
-        // takes an internal format as a parameter. The OES FBO extension and
-        // 2.0 spec don't refer to BGRA as it's not part of the core. One ES
-        // BGRA extensions adds BGRA as both an internal and external format
-        // and the other only as an external format (like desktop GL). OES
-        // restricts RenderbufferStorage's format to a *sized* internal format.
-        // There is no sized BGRA internal format.
-        // So if the texture has internal format BGRA we just hope that the
-        // resolve blit can do RGBA->BGRA internal format conversion.
-        case kRGBA_8888_PM_GrPixelConfig:
-        case kRGBA_8888_UPM_GrPixelConfig:
-        case kBGRA_8888_PM_GrPixelConfig:
-        case kBGRA_8888_UPM_GrPixelConfig:
-            if (fGLCaps.fRGBA8RenderbufferSupport) {
-                // The GL_OES_rgba8_rgb8 extension defines GL_RGBA8 as a sized
-                // internal format.
-                *format = GR_GL_RGBA8;
-                return true;
-            } else {
-                return false;
-            }
-        case kRGB_565_GrPixelConfig:
-            // ES2 supports 565, but desktop GL does not.
-            if (kDesktop_GrGLBinding != this->glBinding()) {
-                *format = GR_GL_RGB565;
-                return true;
-            } else {
-                return false;
-            }
-        case kRGBA_4444_GrPixelConfig:
-            *format = GR_GL_RGBA4;
-            return true;
-        default:
-            return false;
-    }
-}
-
 void GrGpuGL::resetDirtyFlags() {
     Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
 }
diff --git a/src/gpu/GrGpuGL.h b/src/gpu/GrGpuGL.h
index 5f9180f..36fead1 100644
--- a/src/gpu/GrGpuGL.h
+++ b/src/gpu/GrGpuGL.h
@@ -58,7 +58,8 @@
             , fUnpackFlipYSupport(false)
             , fPackRowLengthSupport(false)
             , fPackFlipYSupport(false)
-            , fTextureUsageSupport(false) {
+            , fTextureUsageSupport(false)
+            , fTexStorageSupport(false) {
             memset(fAASamples, 0, sizeof(fAASamples));
         }
         SkTArray<GrGLStencilBuffer::Format, true> fStencilFormats;
@@ -117,6 +118,9 @@
         // Is there support for texture parameter GL_TEXTURE_USAGE
         bool fTextureUsageSupport;
 
+        // Is there support for glTexStorage
+        bool fTexStorageSupport;
+
         void print() const;
     } fGLCaps;
  
@@ -279,10 +283,11 @@
 
     void resolveRenderTarget(GrGLRenderTarget* texture);
 
-    bool canBeTexture(GrPixelConfig config,
-                      GrGLenum* internalFormat,
-                      GrGLenum* externalFormat,
-                      GrGLenum* externalType);
+    bool configToGLFormats(GrPixelConfig config,
+                           bool getSizedInternal,
+                           GrGLenum* internalFormat,
+                           GrGLenum* externalFormat,
+                           GrGLenum* externalType);
     // helper for onCreateTexture and writeTexturePixels
     bool uploadTexData(const GrGLTexture::Desc& desc,
                        bool isNewTexture,
@@ -295,8 +300,6 @@
                                    GrGLuint texID,
                                    GrGLRenderTarget::Desc* desc);
 
-    bool fboInternalFormat(GrPixelConfig config, GrGLenum* format);
-
     friend class GrGLVertexBuffer;
     friend class GrGLIndexBuffer;
     friend class GrGLTexture;
diff --git a/src/gpu/android/GrGLCreateNativeInterface_android.cpp b/src/gpu/android/GrGLCreateNativeInterface_android.cpp
index 5cfb51b..5147627 100644
--- a/src/gpu/android/GrGLCreateNativeInterface_android.cpp
+++ b/src/gpu/android/GrGLCreateNativeInterface_android.cpp
@@ -77,6 +77,11 @@
         interface->fTexImage2D = glTexImage2D;
         interface->fTexParameteri = glTexParameteri;
         interface->fTexSubImage2D = glTexSubImage2D;
+#if GL_ARB_texture_storage
+        interface->fTexStorage2D = glTexStorage2D;
+#elif GL_EXT_texture_storage
+        interface->fTexStorage2D = glTexStorage2DEXT;
+#endif
         interface->fUniform1f = glUniform1f;
         interface->fUniform1i = glUniform1i;
         interface->fUniform1fv = glUniform1fv;
diff --git a/src/gpu/ios/GrGLDefaultInterface_iOS.cpp b/src/gpu/ios/GrGLDefaultInterface_iOS.cpp
index 0060c21..189fb25 100644
--- a/src/gpu/ios/GrGLDefaultInterface_iOS.cpp
+++ b/src/gpu/ios/GrGLDefaultInterface_iOS.cpp
@@ -78,6 +78,11 @@
         // mac uses GLenum for internalFormat param (non-standard)
         // amounts to int vs. uint.
         interface->fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
+    #if GL_ARB_texture_storage
+        interface->fTexStorage2D = glTexStorage2D;
+    #elif GL_EXT_texture_storage
+        interface->fTexStorage2D = glTexStorage2DEXT;
+    #endif
         interface->fTexParameteri = glTexParameteri;
         interface->fTexSubImage2D = glTexSubImage2D;
         interface->fUniform1f = glUniform1f;
diff --git a/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp b/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp
index c8258da..ae2d274 100644
--- a/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp
+++ b/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp
@@ -119,6 +119,18 @@
         // amounts to int vs. uint.
         interface->fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
         interface->fTexParameteri = glTexParameteri;
+    #if GL_ARB_texture_storage || GL_VERSION_4_2
+        interface->fTexStorage2D = glTexStorage2D
+    #elif GL_EXT_texture_storage
+        interface->fTexStorage2D = glTexStorage2DEXT;
+    #else
+        if (glVer >= GR_GL_VER(4,2) ||
+            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+            GR_GL_GET_PROC(TexStorage2D);
+        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+            GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+        }
+    #endif
         interface->fTexSubImage2D = glTexSubImage2D;
         interface->fUniform1f = glUniform1f;
         interface->fUniform1i = glUniform1i;
diff --git a/src/gpu/mesa/GrGLCreateMesaInterface.cpp b/src/gpu/mesa/GrGLCreateMesaInterface.cpp
index 596431c..7303d1b 100644
--- a/src/gpu/mesa/GrGLCreateMesaInterface.cpp
+++ b/src/gpu/mesa/GrGLCreateMesaInterface.cpp
@@ -112,6 +112,10 @@
         GR_GL_GET_PROC(StencilOpSeparate);
         GR_GL_GET_PROC(TexImage2D)
         GR_GL_GET_PROC(TexParameteri);
+        GR_GL_GET_PROC(TexStorage2D);
+        if (NULL == interface->fTexStorage2D) {
+            GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+        }
         GR_GL_GET_PROC(TexSubImage2D);
         GR_GL_GET_PROC(Uniform1f);
         GR_GL_GET_PROC(Uniform1i);
diff --git a/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp b/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp
index 000d667..ab0d351 100644
--- a/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp
+++ b/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp
@@ -112,6 +112,12 @@
         GR_GL_GET_PROC(StencilOpSeparate);
         interface->fTexImage2D = glTexImage2D;
         interface->fTexParameteri = glTexParameteri;
+        if (glVer >= GR_GL_VER(4,2) ||
+            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+            GR_GL_GET_PROC(TexStorage2D);
+        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+            GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+        }
         interface->fTexSubImage2D = glTexSubImage2D;
         GR_GL_GET_PROC(Uniform1f);
         GR_GL_GET_PROC(Uniform1i);
diff --git a/src/gpu/win/GrGLCreateNativeInterface_win.cpp b/src/gpu/win/GrGLCreateNativeInterface_win.cpp
index c67618c..b59f930 100644
--- a/src/gpu/win/GrGLCreateNativeInterface_win.cpp
+++ b/src/gpu/win/GrGLCreateNativeInterface_win.cpp
@@ -72,6 +72,12 @@
         interface->fStencilOp = glStencilOp;
         interface->fTexImage2D = glTexImage2D;
         interface->fTexParameteri = glTexParameteri;
+        if (glVer >= GR_GL_VER(4,2) ||
+            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+            GR_GL_GET_PROC(TexStorage2D);
+        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+            GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+        }
         interface->fTexSubImage2D = glTexSubImage2D;
         interface->fViewport = glViewport;