Add support for GL_EXT_unpack_subimage

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



git-svn-id: http://skia.googlecode.com/svn/trunk@2654 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrGLConfig.h b/include/gpu/GrGLConfig.h
index f9a801d..6d91de6 100644
--- a/include/gpu/GrGLConfig.h
+++ b/include/gpu/GrGLConfig.h
@@ -223,14 +223,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 /**
- *  GrGLResetRowLength() will reset GL_UNPACK_ROW_LENGTH to 0. We write
- *  this wrapper, since GL_UNPACK_ROW_LENGTH is not available on all GL versions
- */
-extern void GrGLResetRowLength(const GrGLInterface*);
-
-////////////////////////////////////////////////////////////////////////////////
-
-/**
  *  Some drivers want the var-int arg to be zero-initialized on input.
  */
 #define GR_GL_INIT_ZERO     0
diff --git a/src/gpu/GrGLTexture.cpp b/src/gpu/GrGLTexture.cpp
index 34ddb85..2a0d5d6 100644
--- a/src/gpu/GrGLTexture.cpp
+++ b/src/gpu/GrGLTexture.cpp
@@ -133,12 +133,12 @@
     /*
      *  check whether to allocate a temporary buffer for flipping y or
      *  because our srcData has extra bytes past each row. If so, we need
-     *  to trim those off here, since GL ES doesn't let us specify
+     *  to trim those off here, since GL ES may not let us specify
      *  GL_UNPACK_ROW_LENGTH.
      */
     bool restoreGLRowLength = false;
     bool flipY = kBottomUp_Orientation == fOrientation;
-    if (kDesktop_GrGLBinding == GPUGL->glBinding() && !flipY) {
+    if (GPUGL->glCaps().fUnpackRowLengthSupport && !flipY) {
         // can't use this for flipping, only non-neg values allowed. :(
         if (srcData && rowBytes != trimRowBytes) {
             GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
@@ -176,10 +176,9 @@
     GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, x, y, width, height,
                           fUploadFormat, fUploadType, srcData));
 
-    if (kDesktop_GrGLBinding == GPUGL->glBinding()) {
-        if (restoreGLRowLength) {
-            GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
-        }
+    if (restoreGLRowLength) {
+        GrAssert(GPUGL->glCaps().fUnpackRowLengthSupport);
+        GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
     }
 }
 
diff --git a/src/gpu/GrGLUtil.cpp b/src/gpu/GrGLUtil.cpp
index 8056e66..f12b407 100644
--- a/src/gpu/GrGLUtil.cpp
+++ b/src/gpu/GrGLUtil.cpp
@@ -30,12 +30,6 @@
     }
 }
 
-void GrGLResetRowLength(const GrGLInterface* gl) {
-    if (gl->supportsDesktop()) {
-        GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 #if GR_GL_LOG_CALLS
diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp
index c162e11..ebf33f4 100644
--- a/src/gpu/GrGpuGL.cpp
+++ b/src/gpu/GrGpuGL.cpp
@@ -382,33 +382,43 @@
     }
 
     if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fRGBA8Renderbuffer = true;
+        fGLCaps.fRGBA8RenderbufferSupport = true;
     } else {
-        fGLCaps.fRGBA8Renderbuffer = this->hasExtension("GL_OES_rgb8_rgba8") ||
-                                     this->hasExtension("GL_ARM_rgba8");
+        fGLCaps.fRGBA8RenderbufferSupport =
+                                    this->hasExtension("GL_OES_rgb8_rgba8") ||
+                                    this->hasExtension("GL_ARM_rgba8");
     }
 
 
     if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fBGRAFormat = this->glVersion() >= GR_GL_VER(1,2) ||
-                              this->hasExtension("GL_EXT_bgra");
+        fGLCaps.fBGRAFormatSupport = this->glVersion() >= GR_GL_VER(1,2) ||
+                                     this->hasExtension("GL_EXT_bgra");
     } else {
         bool hasBGRAExt = false;
         if (this->hasExtension("GL_APPLE_texture_format_BGRA8888")) {
-            fGLCaps.fBGRAFormat = true;
+            fGLCaps.fBGRAFormatSupport = true;
         } else if (this->hasExtension("GL_EXT_texture_format_BGRA8888")) {
-            fGLCaps.fBGRAFormat = true;
-            fGLCaps.fBGRAInternalFormat = true;
+            fGLCaps.fBGRAFormatSupport = true;
+            fGLCaps.fBGRAIsInternalFormat = true;
         }
-        GrAssert(fGLCaps.fBGRAFormat ||
+        GrAssert(fGLCaps.fBGRAFormatSupport ||
                  kSkia8888_PM_GrPixelConfig != kBGRA_8888_PM_GrPixelConfig);
     }
 
     if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fTextureSwizzle = this->glVersion() >= GR_GL_VER(3,3) ||
+        fGLCaps.fTextureSwizzleSupport = this->glVersion() >= GR_GL_VER(3,3) ||
                                   this->hasExtension("GL_ARB_texture_swizzle");
     } else {
-        fGLCaps.fTextureSwizzle = false;
+        fGLCaps.fTextureSwizzleSupport = false;
+    }
+
+    if (kDesktop_GrGLBinding == this->glBinding()) {
+        fGLCaps.fUnpackRowLengthSupport = true;
+        fGLCaps.fPackRowLengthSupport = true;
+    } else {
+        fGLCaps.fUnpackRowLengthSupport = this->hasExtension("GL_EXT_unpack_subimage");
+        // no extension for pack row length
+        fGLCaps.fPackRowLengthSupport = false;
     }
 
     if (kDesktop_GrGLBinding == this->glBinding()) {
@@ -836,7 +846,7 @@
      * GL_UNPACK_ROW_LENGTH.
      */
     bool flipY = GrGLTexture::kBottomUp_Orientation == desc.fOrientation;
-    if (kDesktop_GrGLBinding == this->glBinding() && !flipY) {
+    if (this->glCaps().fUnpackRowLengthSupport && !flipY) {
         if (data && rowBytes != trimRowBytes) {
             GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
             GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
@@ -876,7 +886,9 @@
         GL_CALL(CompressedTexImage2D(GR_GL_TEXTURE_2D, 0, desc.fUploadFormat,
                                      desc.fAllocWidth, desc.fAllocHeight,
                                      0, imageSize, data));
-        GrGLResetRowLength(this->glInterface());
+        if (this->glCaps().fUnpackRowLengthSupport) {
+            GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+        }
     } else {
         if (NULL != data && (desc.fAllocWidth != desc.fContentWidth ||
                                 desc.fAllocHeight != desc.fContentHeight)) {
@@ -886,7 +898,9 @@
             GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, 0, 0, desc.fContentWidth,
                                   desc.fContentHeight, desc.fUploadFormat,
                                   desc.fUploadType, data));
-            GrGLResetRowLength(this->glInterface());
+            if (this->glCaps().fUnpackRowLengthSupport) {
+                GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+            }
 
             int extraW = desc.fAllocWidth  - desc.fContentWidth;
             int extraH = desc.fAllocHeight - desc.fContentHeight;
@@ -943,7 +957,9 @@
             GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, internalFormat,
                                desc.fAllocWidth, desc.fAllocHeight, 0,
                                desc.fUploadFormat, desc.fUploadType, data));
-            GrGLResetRowLength(this->glInterface());
+            if (this->glCaps().fUnpackRowLengthSupport) {
+                GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+            }
         }
     }
 }
@@ -1485,14 +1501,11 @@
                                         int width, int height,
                                         GrPixelConfig config,
                                         size_t rowBytes) {
-    if (kDesktop_GrGLBinding == this->glBinding()) {
-        return false;
-    } else {
-        // On ES we'll have to do memcpys to handle rowByte padding. So, we
-        // might as well flipY while we're at it.
-        return 0 == rowBytes ||
-               GrBytesPerPixel(config) * width == rowBytes; 
-    }
+    // if we have to do memcpy to handle non-trim rowBytes then we
+    // get the flip for free. Otherwise it costs.
+    return this->glCaps().fPackRowLengthSupport ||
+           0 == rowBytes ||
+           GrBytesPerPixel(config) * width == rowBytes;
 }
 
 bool GrGpuGL::onReadPixels(GrRenderTarget* target,
@@ -1547,7 +1560,7 @@
     // a scratch buffer.
     SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
     if (rowBytes != tightRowBytes) {
-        if (kDesktop_GrGLBinding == this->glBinding()) {
+        if (this->glCaps().fPackRowLengthSupport) {
             GrAssert(!(rowBytes % sizeof(GrColor)));
             GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowBytes / sizeof(GrColor)));
             readDstRowBytes = rowBytes;
@@ -1560,6 +1573,7 @@
                        readRect.fWidth, readRect.fHeight,
                        format, type, readDst));
     if (readDstRowBytes != tightRowBytes) {
+        GrAssert(this->glCaps().fPackRowLengthSupport);
         GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
     }
 
@@ -2155,7 +2169,7 @@
                                         GR_GL_TEXTURE_WRAP_T,
                                         newTexParams.fWrapT));
             }
-            if (this->glCaps().fTextureSwizzle &&
+            if (this->glCaps().fTextureSwizzleSupport &&
                 (setAll ||
                  memcmp(newTexParams.fSwizzleRGBA,
                         oldTexParams.fSwizzleRGBA,
@@ -2297,11 +2311,11 @@
             break;
         case kBGRA_8888_PM_GrPixelConfig:
         case kBGRA_8888_UPM_GrPixelConfig:
-            if (!fGLCaps.fBGRAFormat) {
+            if (!fGLCaps.fBGRAFormatSupport) {
                 return false;
             }
             *format = GR_GL_BGRA;
-            if (fGLCaps.fBGRAInternalFormat) {
+            if (fGLCaps.fBGRAIsInternalFormat) {
                 *internalFormat = GR_GL_BGRA;
             } else {
                 *internalFormat = GR_GL_RGBA;
@@ -2374,7 +2388,7 @@
         case kRGBA_8888_UPM_GrPixelConfig:
         case kBGRA_8888_PM_GrPixelConfig:
         case kBGRA_8888_UPM_GrPixelConfig:
-            if (fGLCaps.fRGBA8Renderbuffer) {
+            if (fGLCaps.fRGBA8RenderbufferSupport) {
                 // The GL_OES_rgba8_rgb8 extension defines GL_RGBA8 as a sized
                 // internal format.
                 *format = GR_GL_RGBA8;
@@ -2497,9 +2511,13 @@
     }
     GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
     GrPrintf("Support RGBA8 Render Buffer: %s\n",
-             (fRGBA8Renderbuffer ? "YES": "NO"));
+             (fRGBA8RenderbufferSupport ? "YES": "NO"));
     GrPrintf("BGRA is an internal format: %s\n",
-             (fBGRAInternalFormat ? "YES": "NO"));
+             (fBGRAIsInternalFormat ? "YES": "NO"));
     GrPrintf("Support texture swizzle: %s\n",
-             (fTextureSwizzle ? "YES": "NO"));
+             (fTextureSwizzleSupport ? "YES": "NO"));
+    GrPrintf("Unpack Row length support: %s\n",
+             (fUnpackRowLengthSupport ? "YES": "NO"));
+    GrPrintf("Pack Row length support: %s\n",
+             (fPackRowLengthSupport ? "YES": "NO"));
 }
diff --git a/src/gpu/GrGpuGL.h b/src/gpu/GrGpuGL.h
index 84c62f8..b5b5b15 100644
--- a/src/gpu/GrGpuGL.h
+++ b/src/gpu/GrGpuGL.h
@@ -48,10 +48,12 @@
             : fStencilFormats(8) // prealloc space for    stencil formats
             , fMSFBOType(kNone_MSFBO)
             , fMaxFragmentUniformVectors(0)
-            , fRGBA8Renderbuffer(false)
-            , fBGRAFormat(false)
-            , fBGRAInternalFormat(false)
-            , fTextureSwizzle(false) {
+            , fRGBA8RenderbufferSupport(false)
+            , fBGRAFormatSupport(false)
+            , fBGRAIsInternalFormat(false)
+            , fTextureSwizzleSupport(false)
+            , fUnpackRowLengthSupport(false)
+            , fPackRowLengthSupport(false) {
             memset(fAASamples, 0, sizeof(fAASamples));
         }
         SkTArray<GrGLStencilBuffer::Format, true> fStencilFormats;
@@ -82,19 +84,25 @@
         int fMaxFragmentUniformVectors;
 
         // ES requires an extension to support RGBA8 in RenderBufferStorage
-        bool fRGBA8Renderbuffer;
+        bool fRGBA8RenderbufferSupport;
 
         // Is GL_BGRA supported
-        bool fBGRAFormat;
+        bool fBGRAFormatSupport;
 
         // Depending on the ES extensions present the BGRA external format may
         // correspond either a BGRA or RGBA internalFormat. On desktop GL it is
         // RGBA
-        bool fBGRAInternalFormat;
+        bool fBGRAIsInternalFormat;
 
         // GL_ARB_texture_swizzle support
-        bool fTextureSwizzle;
+        bool fTextureSwizzleSupport;
     
+        // Is there support for GL_UNPACK_ROW_LENGTH
+        bool fUnpackRowLengthSupport;
+
+        // Is there support for GL_PACK_ROW_LENGTH
+        bool fPackRowLengthSupport;
+        
         void print() const;
     } fGLCaps;
  
diff --git a/src/gpu/GrGpuGLShaders.cpp b/src/gpu/GrGpuGLShaders.cpp
index 0961548..67b1c37 100644
--- a/src/gpu/GrGpuGLShaders.cpp
+++ b/src/gpu/GrGpuGLShaders.cpp
@@ -1001,7 +1001,7 @@
                 stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
             }
 
-            if (!this->glCaps().fTextureSwizzle) {
+            if (!this->glCaps().fTextureSwizzleSupport) {
                 if (GrPixelConfigIsAlphaOnly(texture->config())) {
                     // if we don't have texture swizzle support then
                     // the shader must do an alpha smear after reading