Recommit r2584 with gpu pass of the new ReadPixels test disabled in fixed pt (gpu code doesn't work in general in fixed pt).



git-svn-id: http://skia.googlecode.com/svn/trunk@2586 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp
index 7865592..dc4d78a 100644
--- a/src/gpu/GrGpuGL.cpp
+++ b/src/gpu/GrGpuGL.cpp
@@ -1384,14 +1384,18 @@
 }
 
 bool GrGpuGL::onReadPixels(GrRenderTarget* target,
-                           int left, int top, int width, int height,
-                           GrPixelConfig config, void* buffer) {
+                           int left, int top,
+                           int width, int height,
+                           GrPixelConfig config, 
+                           void* buffer, size_t rowBytes) {
     GrGLenum internalFormat;  // we don't use this for glReadPixels
     GrGLenum format;
     GrGLenum type;
     if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
         return false;
-    }    
+    }
+    
+    // resolve the render target if necessary
     GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
     GrAutoTPtrValueRestore<GrRenderTarget*> autoTargetRestore;
     switch (tgt->getResolveType()) {
@@ -1417,26 +1421,62 @@
     // the read rect is viewport-relative
     GrGLIRect readRect;
     readRect.setRelativeTo(glvp, left, top, width, height);
+    
+    size_t tightRowBytes = GrBytesPerPixel(config) * width;
+    if (0 == rowBytes) {
+        rowBytes = tightRowBytes;
+    }
+    size_t readDstRowBytes = tightRowBytes;
+    void* readDst = buffer;
+    
+    // determine if GL can read using the passed rowBytes or if we need
+    // a scratch buffer.
+    SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
+    if (rowBytes != tightRowBytes) {
+        if (kDesktop_GrGLBinding == this->glBinding()) {
+            GrAssert(!(rowBytes % sizeof(GrColor)));
+            GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowBytes / sizeof(GrColor)));
+            readDstRowBytes = rowBytes;
+        } else {
+            scratch.reset(tightRowBytes * height);
+            readDst = scratch.get();
+        }
+    }
     GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom,
                        readRect.fWidth, readRect.fHeight,
-                       format, type, buffer));
+                       format, type, readDst));
+    if (readDstRowBytes != tightRowBytes) {
+        GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
+    }
 
     // now reverse the order of the rows, since GL's are bottom-to-top, but our
-    // API presents top-to-bottom
-    {
-        size_t stride = width * GrBytesPerPixel(config);
-        SkAutoMalloc rowStorage(stride);
-        void* tmp = rowStorage.get();
-
+    // API presents top-to-bottom. We must preserve the padding contents. Note
+    // that the above readPixels did not overwrite the padding.
+    if (readDst == buffer) {
+        GrAssert(rowBytes == readDstRowBytes);
+        scratch.reset(tightRowBytes);
+        void* tmpRow = scratch.get();
+        // flip y in-place by rows
         const int halfY = height >> 1;
         char* top = reinterpret_cast<char*>(buffer);
-        char* bottom = top + (height - 1) * stride;
+        char* bottom = top + (height - 1) * rowBytes;
         for (int y = 0; y < halfY; y++) {
-            memcpy(tmp, top, stride);
-            memcpy(top, bottom, stride);
-            memcpy(bottom, tmp, stride);
-            top += stride;
-            bottom -= stride;
+            memcpy(tmpRow, top, tightRowBytes);
+            memcpy(top, bottom, tightRowBytes);
+            memcpy(bottom, tmpRow, tightRowBytes);
+            top += rowBytes;
+            bottom -= rowBytes;
+        }
+    } else {
+        GrAssert(readDst != buffer);
+        // copy from readDst to buffer while flipping y
+        const int halfY = height >> 1;
+        const char* src = reinterpret_cast<const char*>(readDst);
+        char* dst = reinterpret_cast<char*>(buffer) + (height-1) * rowBytes;
+        for (int y = 0; y < height; y++) {
+            memcpy(dst, src, tightRowBytes);
+            src += readDstRowBytes;
+            dst -= rowBytes;
         }
     }
     return true;