Make GrGpu pixel ops functions take SkIRect instead of LTRB params.

Change-Id: Ic4a8a32a434485b84284decbcc5a8f898197169a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/408359
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrDeferredProxyUploader.h b/src/gpu/GrDeferredProxyUploader.h
index 33e62a5..34f077c 100644
--- a/src/gpu/GrDeferredProxyUploader.h
+++ b/src/gpu/GrDeferredProxyUploader.h
@@ -58,8 +58,11 @@
             // If the worker thread was unable to allocate pixels, this check will fail, and we'll
             // end up drawing with an uninitialized mask texture, but at least we won't crash.
             if (this->fPixels.addr()) {
-                writePixelsFn(proxy, 0, 0, this->fPixels.width(), this->fPixels.height(),
-                              pixelColorType, this->fPixels.addr(), this->fPixels.rowBytes());
+                writePixelsFn(proxy,
+                              SkIRect::MakeSize(fPixels.dimensions()),
+                              pixelColorType,
+                              this->fPixels.addr(),
+                              this->fPixels.rowBytes());
             }
             // Upload has finished, so tell the proxy to release this GrDeferredProxyUploader
             proxy->texPriv().resetDeferredUploader();
diff --git a/src/gpu/GrDeferredUpload.h b/src/gpu/GrDeferredUpload.h
index 946787b..8c4f668 100644
--- a/src/gpu/GrDeferredUpload.h
+++ b/src/gpu/GrDeferredUpload.h
@@ -115,9 +115,11 @@
  * Passed to a deferred upload when it is executed, this method allows the deferred upload to
  * actually write its pixel data into a texture.
  */
-using GrDeferredTextureUploadWritePixelsFn =
-        std::function<bool(GrTextureProxy*, int left, int top, int width, int height,
-                           GrColorType srcColorType, const void* buffer, size_t rowBytes)>;
+using GrDeferredTextureUploadWritePixelsFn = std::function<bool(GrTextureProxy*,
+                                                                SkIRect,
+                                                                GrColorType srcColorType,
+                                                                const void*,
+                                                                size_t rowBytes)>;
 
 /**
  * A deferred texture upload is simply a std::function that takes a
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index c562c55..253043e 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -176,8 +176,11 @@
     dataPtr += rowBytes * fDirtyRect.fTop;
     dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
 
-    writePixels(proxy, fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop,
-                fDirtyRect.width(), fDirtyRect.height(), fColorType, dataPtr, rowBytes);
+    writePixels(proxy,
+                fDirtyRect.makeOffset(fOffset.fX, fOffset.fY),
+                fColorType,
+                dataPtr,
+                rowBytes);
     fDirtyRect.setEmpty();
     SkDEBUGCODE(fDirty = false;)
 }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 32d5f60..8afc77d 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -207,8 +207,12 @@
         // Currently if level 0 does not have pixels then no other level may, as enforced by
         // validate_texel_levels.
         if (texelLevelCount && texels[0].fPixels) {
-            if (!this->writePixels(tex.get(), 0, 0, dimensions.fWidth, dimensions.fHeight,
-                                   textureColorType, srcColorType, texels, texelLevelCount)) {
+            if (!this->writePixels(tex.get(),
+                                   SkIRect::MakeSize(dimensions),
+                                   textureColorType,
+                                   srcColorType,
+                                   texels,
+                                   texelLevelCount)) {
                 return nullptr;
             }
             // Currently if level[1] of mip map has pixel data then so must all other levels.
@@ -379,21 +383,22 @@
     return this->onCopySurface(dst, src, srcRect, dstPoint);
 }
 
-bool GrGpu::readPixels(GrSurface* surface, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+bool GrGpu::readPixels(GrSurface* surface,
+                       SkIRect rect,
+                       GrColorType surfaceColorType,
+                       GrColorType dstColorType,
+                       void* buffer,
                        size_t rowBytes) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
     SkASSERT(!surface->framebufferOnly());
     SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
 
-    auto subRect = SkIRect::MakeXYWH(left, top, width, height);
-    auto bounds  = SkIRect::MakeWH(surface->width(), surface->height());
-    if (!bounds.contains(subRect)) {
+    if (!SkIRect::MakeSize(surface->dimensions()).contains(rect)) {
         return false;
     }
 
-    size_t minRowBytes = SkToSizeT(GrColorTypeBytesPerPixel(dstColorType) * width);
+    size_t minRowBytes = SkToSizeT(GrColorTypeBytesPerPixel(dstColorType) * rect.width());
     if (!this->caps()->readPixelsRowBytesSupport()) {
         if (rowBytes != minRowBytes) {
             return false;
@@ -409,13 +414,16 @@
 
     this->handleDirtyContext();
 
-    return this->onReadPixels(surface, left, top, width, height, surfaceColorType, dstColorType,
-                              buffer, rowBytes);
+    return this->onReadPixels(surface, rect, surfaceColorType, dstColorType, buffer, rowBytes);
 }
 
-bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height,
-                        GrColorType surfaceColorType, GrColorType srcColorType,
-                        const GrMipLevel texels[], int mipLevelCount, bool prepForTexSampling) {
+bool GrGpu::writePixels(GrSurface* surface,
+                        SkIRect rect,
+                        GrColorType surfaceColorType,
+                        GrColorType srcColorType,
+                        const GrMipLevel texels[],
+                        int mipLevelCount,
+                        bool prepForTexSampling) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     ATRACE_ANDROID_FRAMEWORK_ALWAYS("Texture upload(%u) %ix%i",
                                     surface->uniqueID().asUInt(), width, height);
@@ -430,25 +438,26 @@
         return false;
     } else if (mipLevelCount == 1) {
         // We require that if we are not mipped, then the write region is contained in the surface
-        auto subRect = SkIRect::MakeXYWH(left, top, width, height);
-        auto bounds  = SkIRect::MakeWH(surface->width(), surface->height());
-        if (!bounds.contains(subRect)) {
+        if (!SkIRect::MakeSize(surface->dimensions()).contains(rect)) {
             return false;
         }
-    } else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) {
+    } else if (rect != SkIRect::MakeSize(surface->dimensions())) {
         // We require that if the texels are mipped, than the write region is the entire surface
         return false;
     }
 
-    if (!validate_texel_levels({width, height}, srcColorType, texels, mipLevelCount,
-                               this->caps())) {
+    if (!validate_texel_levels(rect.size(), srcColorType, texels, mipLevelCount, this->caps())) {
         return false;
     }
 
     this->handleDirtyContext();
-    if (this->onWritePixels(surface, left, top, width, height, surfaceColorType, srcColorType,
-                            texels, mipLevelCount, prepForTexSampling)) {
-        SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
+    if (this->onWritePixels(surface,
+                            rect,
+                            surfaceColorType,
+                            srcColorType,
+                            texels,
+                            mipLevelCount,
+                            prepForTexSampling)) {
         this->didWriteToSurface(surface, kTopLeft_GrSurfaceOrigin, &rect, mipLevelCount);
         fStats.incTextureUploads();
         return true;
@@ -456,9 +465,13 @@
     return false;
 }
 
-bool GrGpu::transferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                             GrColorType textureColorType, GrColorType bufferColorType,
-                             sk_sp<GrGpuBuffer> transferBuffer, size_t offset, size_t rowBytes) {
+bool GrGpu::transferPixelsTo(GrTexture* texture,
+                             SkIRect rect,
+                             GrColorType textureColorType,
+                             GrColorType bufferColorType,
+                             sk_sp<GrGpuBuffer> transferBuffer,
+                             size_t offset,
+                             size_t rowBytes) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(texture);
     SkASSERT(transferBuffer);
@@ -468,30 +481,32 @@
     }
 
     // We require that the write region is contained in the texture
-    SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
-    SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
-    if (!bounds.contains(subRect)) {
+    if (!SkIRect::MakeSize(texture->dimensions()).contains(rect)) {
         return false;
     }
 
     size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
     if (this->caps()->writePixelsRowBytesSupport()) {
-        if (rowBytes < SkToSizeT(bpp * width)) {
+        if (rowBytes < SkToSizeT(bpp*rect.width())) {
             return false;
         }
         if (rowBytes % bpp) {
             return false;
         }
     } else {
-        if (rowBytes != SkToSizeT(bpp * width)) {
+        if (rowBytes != SkToSizeT(bpp*rect.width())) {
             return false;
         }
     }
 
     this->handleDirtyContext();
-    if (this->onTransferPixelsTo(texture, left, top, width, height, textureColorType,
-                                 bufferColorType, std::move(transferBuffer), offset, rowBytes)) {
-        SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
+    if (this->onTransferPixelsTo(texture,
+                                 rect,
+                                 textureColorType,
+                                 bufferColorType,
+                                 std::move(transferBuffer),
+                                 offset,
+                                 rowBytes)) {
         this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect);
         fStats.incTransfersToTexture();
 
@@ -500,9 +515,12 @@
     return false;
 }
 
-bool GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                               GrColorType surfaceColorType, GrColorType bufferColorType,
-                               sk_sp<GrGpuBuffer> transferBuffer, size_t offset) {
+bool GrGpu::transferPixelsFrom(GrSurface* surface,
+                               SkIRect rect,
+                               GrColorType surfaceColorType,
+                               GrColorType bufferColorType,
+                               sk_sp<GrGpuBuffer> transferBuffer,
+                               size_t offset) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
     SkASSERT(transferBuffer);
@@ -516,15 +534,17 @@
 #endif
 
     // We require that the write region is contained in the texture
-    SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
-    SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height());
-    if (!bounds.contains(subRect)) {
+    if (!SkIRect::MakeSize(surface->dimensions()).contains(rect)) {
         return false;
     }
 
     this->handleDirtyContext();
-    if (this->onTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
-                                   bufferColorType, std::move(transferBuffer), offset)) {
+    if (this->onTransferPixelsFrom(surface,
+                                   rect,
+                                   surfaceColorType,
+                                   bufferColorType,
+                                   std::move(transferBuffer),
+                                   offset)) {
         fStats.incTransfersFromSurface();
         return true;
     }
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 7a83519..fbe28a8 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -219,11 +219,8 @@
     /**
      * Reads a rectangle of pixels from a render target. No sRGB/linear conversions are performed.
      *
-     * @param surface           The surface to read from
-     * @param left              left edge of the rectangle to read (inclusive)
-     * @param top               top edge of the rectangle to read (inclusive)
-     * @param width             width of rectangle to read in pixels.
-     * @param height            height of rectangle to read in pixels.
+     * @param surface           the surface to read from
+     * @param rect              the rectangle of pixels to read
      * @param surfaceColorType  the color type for this use of the surface.
      * @param dstColorType      the color type of the destination buffer.
      * @param buffer            memory to read the rectangle into.
@@ -236,18 +233,18 @@
      *              is not allowed for the format of the surface or if the rectangle
      *              read is not contained in the surface.
      */
-    bool readPixels(GrSurface* surface, int left, int top, int width, int height,
-                    GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    bool readPixels(GrSurface* surface,
+                    SkIRect rect,
+                    GrColorType surfaceColorType,
+                    GrColorType dstColorType,
+                    void* buffer,
                     size_t rowBytes);
 
     /**
      * Updates the pixels in a rectangle of a surface.  No sRGB/linear conversions are performed.
      *
-     * @param surface            The surface to write to.
-     * @param left               left edge of the rectangle to write (inclusive)
-     * @param top                top edge of the rectangle to write (inclusive)
-     * @param width              width of rectangle to write in pixels.
-     * @param height             height of rectangle to write in pixels.
+     * @param surface            the surface to write to.
+     * @param rect               the rectangle of pixels to overwrite
      * @param surfaceColorType   the color type for this use of the surface.
      * @param srcColorType       the color type of the source buffer.
      * @param texels             array of mipmap levels containing texture data. Row bytes must be a
@@ -267,41 +264,55 @@
      *              the color type is not allowed for the format of the surface or
      *              if the rectangle written is not contained in the surface.
      */
-    bool writePixels(GrSurface* surface, int left, int top, int width, int height,
-                     GrColorType surfaceColorType, GrColorType srcColorType,
-                     const GrMipLevel texels[], int mipLevelCount, bool prepForTexSampling = false);
+    bool writePixels(GrSurface* surface,
+                     SkIRect rect,
+                     GrColorType surfaceColorType,
+                     GrColorType srcColorType,
+                     const GrMipLevel texels[],
+                     int mipLevelCount,
+                     bool prepForTexSampling = false);
 
     /**
      * Helper for the case of a single level.
      */
-    bool writePixels(GrSurface* surface, int left, int top, int width, int height,
-                     GrColorType surfaceColorType, GrColorType srcColorType, const void* buffer,
-                     size_t rowBytes, bool prepForTexSampling = false) {
+    bool writePixels(GrSurface* surface,
+                     SkIRect rect,
+                     GrColorType surfaceColorType,
+                     GrColorType srcColorType,
+                     const void* buffer,
+                     size_t rowBytes,
+                     bool prepForTexSampling = false) {
         GrMipLevel mipLevel = {buffer, rowBytes, nullptr};
-        return this->writePixels(surface, left, top, width, height, surfaceColorType, srcColorType,
-                                 &mipLevel, 1, prepForTexSampling);
+        return this->writePixels(surface,
+                                 rect,
+                                 surfaceColorType,
+                                 srcColorType,
+                                 &mipLevel,
+                                 1,
+                                 prepForTexSampling);
     }
 
     /**
      * Updates the pixels in a rectangle of a texture using a buffer. If the texture is MIP mapped,
      * the base level is written to.
      *
-     * @param texture          The texture to write to.
-     * @param left             left edge of the rectangle to write (inclusive)
-     * @param top              top edge of the rectangle to write (inclusive)
-     * @param width            width of rectangle to write in pixels.
-     * @param height           height of rectangle to write in pixels.
+     * @param texture          the texture to write to.
+     * @param rect             the rectangle of pixels in the texture to overwrite
      * @param textureColorType the color type for this use of the surface.
      * @param bufferColorType  the color type of the transfer buffer's pixel data
      * @param transferBuffer   GrBuffer to read pixels from (type must be "kXferCpuToGpu")
      * @param offset           offset from the start of the buffer
      * @param rowBytes         number of bytes between consecutive rows in the buffer. Must be a
-     *                         multiple of bufferColorType's bytes-per-pixel. Must be tight to width
-     *                         if !caps->writePixelsRowBytesSupport().
+     *                         multiple of bufferColorType's bytes-per-pixel. Must be tight to
+     *                         rect.width() if !caps->writePixelsRowBytesSupport().
      */
-    bool transferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                          GrColorType textureColorType, GrColorType bufferColorType,
-                          sk_sp<GrGpuBuffer> transferBuffer, size_t offset, size_t rowBytes);
+    bool transferPixelsTo(GrTexture* texture,
+                          SkIRect rect,
+                          GrColorType textureColorType,
+                          GrColorType bufferColorType,
+                          sk_sp<GrGpuBuffer> transferBuffer,
+                          size_t offset,
+                          size_t rowBytes);
 
     /**
      * Reads the pixels from a rectangle of a surface into a buffer. Use
@@ -309,24 +320,24 @@
      * the buffer offset alignment. If the surface is a MIP mapped texture, the base level is read.
      *
      * If successful the row bytes in the buffer is always:
-     *   GrColorTypeBytesPerPixel(bufferColorType) * width
+     *   GrColorTypeBytesPerPixel(bufferColorType) * rect.width()
      *
      * Asserts that the caller has passed a properly aligned offset and that the buffer is
      * large enough to hold the result
      *
-     * @param surface          The surface to read from.
-     * @param left             left edge of the rectangle to read (inclusive)
-     * @param top              top edge of the rectangle to read (inclusive)
-     * @param width            width of rectangle to read in pixels.
-     * @param height           height of rectangle to read in pixels.
+     * @param surface          the surface to read from.
+     * @param rect             the rectangle of pixels to read
      * @param surfaceColorType the color type for this use of the surface.
      * @param bufferColorType  the color type of the transfer buffer's pixel data
      * @param transferBuffer   GrBuffer to write pixels to (type must be "kXferGpuToCpu")
      * @param offset           offset from the start of the buffer
      */
-    bool transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer> transferBuffer, size_t offset);
+    bool transferPixelsFrom(GrSurface* surface,
+                            SkIRect rect,
+                            GrColorType surfaceColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer> transferBuffer,
+                            size_t offset);
 
     // Called to perform a surface to surface copy. Fallbacks to issuing a draw from the src to dst
     // take place at higher levels and this function implement faster copy paths. The rect
@@ -716,24 +727,36 @@
                                               GrAccessPattern, const void* data) = 0;
 
     // overridden by backend-specific derived class to perform the surface read
-    virtual bool onReadPixels(GrSurface*, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    virtual bool onReadPixels(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType dstColorType,
+                              void*,
                               size_t rowBytes) = 0;
 
     // overridden by backend-specific derived class to perform the surface write
-    virtual bool onWritePixels(GrSurface*, int left, int top, int width, int height,
-                               GrColorType surfaceColorType, GrColorType srcColorType,
-                               const GrMipLevel texels[], int mipLevelCount,
+    virtual bool onWritePixels(GrSurface*,
+                               SkIRect,
+                               GrColorType surfaceColorType,
+                               GrColorType srcColorType,
+                               const GrMipLevel[],
+                               int mipLevelCount,
                                bool prepForTexSampling) = 0;
 
     // overridden by backend-specific derived class to perform the texture transfer
-    virtual bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
-                                    GrColorType textiueColorType, GrColorType bufferColorType,
-                                    sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+    virtual bool onTransferPixelsTo(GrTexture*,
+                                    SkIRect,
+                                    GrColorType textiueColorType,
+                                    GrColorType bufferColorType,
+                                    sk_sp<GrGpuBuffer> transferBuffer,
+                                    size_t offset,
                                     size_t rowBytes) = 0;
+
     // overridden by backend-specific derived class to perform the surface transfer
-    virtual bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
-                                      GrColorType surfaceColorType, GrColorType bufferColorType,
+    virtual bool onTransferPixelsFrom(GrSurface*,
+                                      SkIRect,
+                                      GrColorType surfaceColorType,
+                                      GrColorType bufferColorType,
                                       sk_sp<GrGpuBuffer> transferBuffer,
                                       size_t offset) = 0;
 
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index 36f01be..67da4ab 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -100,24 +100,27 @@
 void GrOpFlushState::doUpload(GrDeferredTextureUploadFn& upload,
                               bool shouldPrepareSurfaceForSampling) {
     GrDeferredTextureUploadWritePixelsFn wp = [this, shouldPrepareSurfaceForSampling](
-            GrTextureProxy* dstProxy, int left, int top, int width, int height,
-            GrColorType colorType, const void* buffer, size_t rowBytes) {
+                                                      GrTextureProxy* dstProxy,
+                                                      SkIRect rect,
+                                                      GrColorType colorType,
+                                                      const void* buffer,
+                                                      size_t rowBytes) {
         GrSurface* dstSurface = dstProxy->peekSurface();
         if (!fGpu->caps()->surfaceSupportsWritePixels(dstSurface)) {
             return false;
         }
         GrCaps::SupportedWrite supportedWrite = fGpu->caps()->supportedWritePixelsColorType(
                 colorType, dstSurface->backendFormat(), colorType);
-        size_t tightRB = width * GrColorTypeBytesPerPixel(supportedWrite.fColorType);
+        size_t tightRB = rect.width()*GrColorTypeBytesPerPixel(supportedWrite.fColorType);
         SkASSERT(rowBytes >= tightRB);
         std::unique_ptr<char[]> tmpPixels;
         if (supportedWrite.fColorType != colorType ||
             (!fGpu->caps()->writePixelsRowBytesSupport() && rowBytes != tightRB)) {
-            tmpPixels.reset(new char[height * tightRB]);
+            tmpPixels.reset(new char[rect.height()*tightRB]);
             // Use kUnknown to ensure no alpha type conversions or clamping occur.
             static constexpr auto kAT = kUnknown_SkAlphaType;
-            GrImageInfo srcInfo(colorType,                 kAT, nullptr, width, height);
-            GrImageInfo tmpInfo(supportedWrite.fColorType, kAT, nullptr, width, height);
+            GrImageInfo srcInfo(colorType,                 kAT, nullptr, rect.size());
+            GrImageInfo tmpInfo(supportedWrite.fColorType, kAT, nullptr, rect.size());
             if (!GrConvertPixels( GrPixmap(tmpInfo, tmpPixels.get(), tightRB ),
                                  GrCPixmap(srcInfo,          buffer, rowBytes))) {
                 return false;
@@ -125,8 +128,12 @@
             rowBytes = tightRB;
             buffer = tmpPixels.get();
         }
-        return this->fGpu->writePixels(dstSurface, left, top, width, height, colorType,
-                                       supportedWrite.fColorType, buffer, rowBytes,
+        return this->fGpu->writePixels(dstSurface,
+                                       rect,
+                                       colorType,
+                                       supportedWrite.fColorType,
+                                       buffer,
+                                       rowBytes,
                                        shouldPrepareSurfaceForSampling);
     };
     upload(wp);
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 38738a5..4e52763 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -728,7 +728,11 @@
     if (tempColorType == GrColorType::kUnknown) {
         return nullptr;
     }
-    SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
-                                     colorType, tempColorType, tmpTexels.get(), mipLevelCount));
+    SkAssertResult(fGpu->writePixels(texture.get(),
+                                     SkIRect::MakeSize(baseSize),
+                                     colorType,
+                                     tempColorType,
+                                     tmpTexels.get(),
+                                     mipLevelCount));
     return texture;
 }
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 94682af..bc708d8 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -343,9 +343,12 @@
 
     dContext->priv().flushSurface(srcProxy.get());
     dContext->submit();
-    if (!dContext->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dst.width(), dst.height(),
+    if (!dContext->priv().getGpu()->readPixels(srcSurface,
+                                               SkIRect::MakePtSize(pt, dst.dimensions()),
                                                this->colorInfo().colorType(),
-                                               supportedRead.fColorType, readDst, readRB)) {
+                                               supportedRead.fColorType,
+                                               readDst,
+                                               readRB)) {
         return false;
     }
 
diff --git a/src/gpu/GrTransferFromRenderTask.cpp b/src/gpu/GrTransferFromRenderTask.cpp
index 4c1d848..0c679ed 100644
--- a/src/gpu/GrTransferFromRenderTask.cpp
+++ b/src/gpu/GrTransferFromRenderTask.cpp
@@ -24,7 +24,10 @@
     if (!fSrcProxy->isInstantiated()) {
         return false;
     }
-    return flushState->gpu()->transferPixelsFrom(
-            fSrcProxy->peekSurface(), fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.width(),
-            fSrcRect.height(), fSurfaceColorType, fDstColorType, fDstBuffer, fDstOffset);
+    return flushState->gpu()->transferPixelsFrom(fSrcProxy->peekSurface(),
+                                                 fSrcRect,
+                                                 fSurfaceColorType,
+                                                 fDstColorType,
+                                                 fDstBuffer,
+                                                 fDstOffset);
 }
diff --git a/src/gpu/GrWritePixelsRenderTask.cpp b/src/gpu/GrWritePixelsRenderTask.cpp
index e8caeb2..1b2c37e 100644
--- a/src/gpu/GrWritePixelsRenderTask.cpp
+++ b/src/gpu/GrWritePixelsRenderTask.cpp
@@ -61,10 +61,7 @@
     }
     GrSurface* dstSurface = dstProxy->peekSurface();
     return flushState->gpu()->writePixels(dstSurface,
-                                          fRect.fLeft,
-                                          fRect.fTop,
-                                          fRect.width(),
-                                          fRect.height(),
+                                          fRect,
                                           fDstColorType,
                                           fSrcColorType,
                                           fLevels.get(),
diff --git a/src/gpu/d3d/GrD3DGpu.cpp b/src/gpu/d3d/GrD3DGpu.cpp
index 1567e91..5067b1b 100644
--- a/src/gpu/d3d/GrD3DGpu.cpp
+++ b/src/gpu/d3d/GrD3DGpu.cpp
@@ -556,8 +556,11 @@
     this->resolveTexture(target, resolveRect.fLeft, resolveRect.fTop, rt, resolveRect);
 }
 
-bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+bool GrD3DGpu::onReadPixels(GrSurface* surface,
+                            SkIRect rect,
+                            GrColorType surfaceColorType,
+                            GrColorType dstColorType,
+                            void* buffer,
                             size_t rowBytes) {
     SkASSERT(surface);
 
@@ -588,8 +591,7 @@
                                                            GrGpuBufferType::kXferGpuToCpu,
                                                            kDynamic_GrAccessPattern);
 
-    this->readOrTransferPixels(texResource, left, top, width, height, transferBuffer,
-                               placedFootprint);
+    this->readOrTransferPixels(texResource, rect, transferBuffer, placedFootprint);
     this->submitDirectCommandList(SyncQueue::kForce);
 
     // Copy back to CPU buffer
@@ -597,12 +599,16 @@
     if (GrDxgiFormatBytesPerBlock(texResource->dxgiFormat()) != bpp) {
         return false;
     }
-    size_t tightRowBytes = bpp * width;
+    size_t tightRowBytes = bpp * rect.width();
 
     const void* mappedMemory = transferBuffer->map();
 
-    SkRectMemcpy(buffer, rowBytes, mappedMemory, placedFootprint.Footprint.RowPitch,
-                 tightRowBytes, height);
+    SkRectMemcpy(buffer,
+                 rowBytes,
+                 mappedMemory,
+                 placedFootprint.Footprint.RowPitch,
+                 tightRowBytes,
+                 rect.height());
 
     transferBuffer->unmap();
 
@@ -610,7 +616,7 @@
 }
 
 void GrD3DGpu::readOrTransferPixels(GrD3DTextureResource* texResource,
-                                    int left, int top, int width, int height,
+                                    SkIRect rect,
                                     sk_sp<GrGpuBuffer> transferBuffer,
                                     const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& placedFootprint) {
     // Set up src location and box
@@ -621,10 +627,10 @@
     srcLocation.SubresourceIndex = 0;
 
     D3D12_BOX srcBox = {};
-    srcBox.left = left;
-    srcBox.top = top;
-    srcBox.right = left + width;
-    srcBox.bottom = top + height;
+    srcBox.left = rect.left();
+    srcBox.top = rect.top();
+    srcBox.right = rect.right();
+    srcBox.bottom = rect.bottom();
     srcBox.front = 0;
     srcBox.back = 1;
 
@@ -643,9 +649,12 @@
                                                          &srcBox);
 }
 
-bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                             GrColorType surfaceColorType, GrColorType srcColorType,
-                             const GrMipLevel texels[], int mipLevelCount,
+bool GrD3DGpu::onWritePixels(GrSurface* surface,
+                             SkIRect rect,
+                             GrColorType surfaceColorType,
+                             GrColorType srcColorType,
+                             const GrMipLevel texels[],
+                             int mipLevelCount,
                              bool prepForTexSampling) {
     GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
     if (!d3dTex) {
@@ -664,8 +673,7 @@
     d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
 
     SkASSERT(mipLevelCount <= d3dTex->maxMipmapLevel() + 1);
-    success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
-                                    mipLevelCount);
+    success = this->uploadToTexture(d3dTex, rect, srcColorType, texels, mipLevelCount);
 
     if (prepForTexSampling) {
         d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
@@ -674,18 +682,20 @@
     return success;
 }
 
-bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
-                               GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
+bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex,
+                               SkIRect rect,
+                               GrColorType colorType,
+                               const GrMipLevel* texels,
+                               int mipLevelCount) {
     SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
-    SkASSERT(1 == mipLevelCount ||
-             (0 == left && 0 == top && width == tex->width() && height == tex->height()));
+    SkASSERT(mipLevelCount == 1 || rect == SkIRect::MakeSize(tex->dimensions()));
 
     // We assume that if the texture has mip levels, we either upload to all the levels or just the
     // first.
-    SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->maxMipmapLevel() + 1));
+    SkASSERT(mipLevelCount == 1 || mipLevelCount == (tex->maxMipmapLevel() + 1));
 
-    if (width == 0 || height == 0) {
+    if (rect.isEmpty()) {
         return false;
     }
 
@@ -713,8 +723,8 @@
     UINT64 combinedBufferSize;
     // We reset the width and height in the description to match our subrectangle size
     // so we don't end up allocating more space than we need.
-    desc.Width = width;
-    desc.Height = height;
+    desc.Width = rect.width();
+    desc.Height = rect.height();
     fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
                                    nullptr, nullptr, &combinedBufferSize);
     size_t bpp = GrColorTypeBytesPerPixel(colorType);
@@ -728,8 +738,8 @@
 
     char* bufferData = (char*)slice.fOffsetMapPtr;
 
-    int currentWidth = width;
-    int currentHeight = height;
+    int currentWidth = rect.width();
+    int currentHeight = rect.height();
     int layerHeight = tex->height();
 
     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
@@ -757,8 +767,12 @@
     }
 
     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
-    fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
-                                                   placedFootprints.get(), left, top);
+    fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer,
+                                                   tex,
+                                                   mipLevelCount,
+                                                   placedFootprints.get(),
+                                                   rect.left(),
+                                                   rect.top());
 
     if (mipLevelCount < (int)desc.MipLevels) {
         tex->markMipmapsDirty();
@@ -767,9 +781,12 @@
     return true;
 }
 
-bool GrD3DGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                  GrColorType surfaceColorType, GrColorType bufferColorType,
-                                  sk_sp<GrGpuBuffer> transferBuffer, size_t bufferOffset,
+bool GrD3DGpu::onTransferPixelsTo(GrTexture* texture,
+                                  SkIRect rect,
+                                  GrColorType surfaceColorType,
+                                  GrColorType bufferColorType,
+                                  sk_sp<GrGpuBuffer> transferBuffer,
+                                  size_t bufferOffset,
                                   size_t rowBytes) {
     if (!this->currentCommandList()) {
         return false;
@@ -801,19 +818,15 @@
 
     SkASSERT(GrDxgiFormatBytesPerBlock(format) == GrColorTypeBytesPerPixel(bufferColorType));
 
-    SkDEBUGCODE(
-        SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
-        SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
-        SkASSERT(bounds.contains(subRect));
-        )
+    SkASSERT(SkIRect::MakeSize(texture->dimensions()).contains(rect));
 
     // Set up copy region
     D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedFootprint = {};
     ID3D12Resource* d3dResource = d3dTex->d3dResource();
     SkASSERT(d3dResource);
     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
-    desc.Width = width;
-    desc.Height = height;
+    desc.Width = rect.width();
+    desc.Height = rect.height();
     UINT64 totalBytes;
     fDevice->GetCopyableFootprints(&desc, 0, 1, 0, &placedFootprint,
                                    nullptr, nullptr, &totalBytes);
@@ -824,17 +837,24 @@
 
     // Copy the buffer to the image.
     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get())->d3dResource();
-    fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, d3dTex, 1,
-                                                   &placedFootprint, left, top);
+    fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer,
+                                                   d3dTex,
+                                                   1,
+                                                   &placedFootprint,
+                                                   rect.left(),
+                                                   rect.top());
     this->currentCommandList()->addGrBuffer(std::move(transferBuffer));
 
     d3dTex->markMipmapsDirty();
     return true;
 }
 
-bool GrD3DGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                    GrColorType surfaceColorType, GrColorType bufferColorType,
-                                    sk_sp<GrGpuBuffer> transferBuffer, size_t offset) {
+bool GrD3DGpu::onTransferPixelsFrom(GrSurface* surface,
+                                    SkIRect rect,
+                                    GrColorType surfaceColorType,
+                                    GrColorType bufferColorType,
+                                    sk_sp<GrGpuBuffer> transferBuffer,
+                                    size_t offset) {
     if (!this->currentCommandList()) {
         return false;
     }
@@ -866,16 +886,15 @@
     SkASSERT(GrDxgiFormatBytesPerBlock(format) == GrColorTypeBytesPerPixel(bufferColorType));
 
     D3D12_RESOURCE_DESC desc = texResource->d3dResource()->GetDesc();
-    desc.Width = width;
-    desc.Height = height;
+    desc.Width = rect.width();
+    desc.Height = rect.height();
     D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedFootprint;
     UINT64 transferTotalBytes;
     fDevice->GetCopyableFootprints(&desc, 0, 1, offset, &placedFootprint,
                                    nullptr, nullptr, &transferTotalBytes);
     SkASSERT(transferTotalBytes);
 
-    this->readOrTransferPixels(texResource, left, top, width, height,
-                               transferBuffer, placedFootprint);
+    this->readOrTransferPixels(texResource, rect, transferBuffer, placedFootprint);
 
     // TODO: It's not clear how to ensure the transfer is done before we read from the buffer,
     // other than maybe doing a resource state transition.
diff --git a/src/gpu/d3d/GrD3DGpu.h b/src/gpu/d3d/GrD3DGpu.h
index d4a51bf..303eed1 100644
--- a/src/gpu/d3d/GrD3DGpu.h
+++ b/src/gpu/d3d/GrD3DGpu.h
@@ -165,22 +165,35 @@
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t sizeInBytes, GrGpuBufferType, GrAccessPattern,
                                       const void*) override;
 
-    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    bool onReadPixels(GrSurface*,
+                      SkIRect,
+                      GrColorType surfaceColorType,
+                      GrColorType dstColorType,
+                      void*,
                       size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType srcColorType,
-                       const GrMipLevel texels[], int mipLevelCount,
+    bool onWritePixels(GrSurface*,
+                       SkIRect,
+                       GrColorType surfaceColorType,
+                       GrColorType srcColorType,
+                       const GrMipLevel[],
+                       int mipLevelCount,
                        bool prepForTexSampling) override;
 
-    bool onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+    bool onTransferPixelsTo(GrTexture*,
+                            SkIRect,
+                            GrColorType surfaceColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer>,
+                            size_t offset,
                             size_t rowBytes) override;
-    bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType bufferColorType,
-                              sk_sp<GrGpuBuffer> transferBuffer, size_t offset) override;
+
+    bool onTransferPixelsFrom(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType bufferColorType,
+                              sk_sp<GrGpuBuffer>,
+                              size_t offset) override;
 
     bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
                        const SkIPoint& dstPoint) override;
@@ -253,11 +266,14 @@
                                          int mipLevelCount,
                                          GrMipmapStatus);
 
-    bool uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
-                         GrColorType colorType, const GrMipLevel* texels, int mipLevelCount);
+    bool uploadToTexture(GrD3DTexture* tex,
+                         SkIRect rect,
+                         GrColorType colorType,
+                         const GrMipLevel texels[],
+                         int mipLevelCount);
 
     void readOrTransferPixels(GrD3DTextureResource* texResource,
-                              int left, int top, int width, int height,
+                              SkIRect rect,
                               sk_sp<GrGpuBuffer> transferBuffer,
                               const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& placedFootprint);
 
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
index 537636b..44f3103 100644
--- a/src/gpu/dawn/GrDawnGpu.cpp
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -178,33 +178,41 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-bool GrDawnGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType srcColorType,
-                              const GrMipLevel texels[], int mipLevelCount,
+bool GrDawnGpu::onWritePixels(GrSurface* surface,
+                              SkIRect rect,
+                              GrColorType surfaceColorType,
+                              GrColorType srcColorType,
+                              const GrMipLevel texels[],
+                              int mipLevelCount,
                               bool prepForTexSampling) {
     GrDawnTexture* texture = static_cast<GrDawnTexture*>(surface->asTexture());
     if (!texture) {
         return false;
     }
-    this->uploadTextureData(srcColorType, texels, mipLevelCount,
-                            SkIRect::MakeXYWH(left, top, width, height), texture->texture());
+    this->uploadTextureData(srcColorType, texels, mipLevelCount, rect, texture->texture());
     if (mipLevelCount < texture->maxMipmapLevel() + 1) {
         texture->markMipmapsDirty();
     }
     return true;
 }
 
-bool GrDawnGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                   GrColorType textureColorType, GrColorType bufferColorType,
-                                   sk_sp<GrGpuBuffer> transferBuffer, size_t bufferOffset,
+bool GrDawnGpu::onTransferPixelsTo(GrTexture* texture,
+                                   SkIRect rect,
+                                   GrColorType textureColorType,
+                                   GrColorType bufferColorType,
+                                   sk_sp<GrGpuBuffer> transferBuffer,
+                                   size_t bufferOffset,
                                    size_t rowBytes) {
     SkASSERT(!"unimplemented");
     return false;
 }
 
-bool GrDawnGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                     GrColorType surfaceColorType, GrColorType bufferColorType,
-                                     sk_sp<GrGpuBuffer> transferBuffer, size_t offset) {
+bool GrDawnGpu::onTransferPixelsFrom(GrSurface* surface,
+                                     SkIRect rect,
+                                     GrColorType surfaceColorType,
+                                     GrColorType bufferColorType,
+                                     sk_sp<GrGpuBuffer> transferBuffer,
+                                     size_t offset) {
     SkASSERT(!"unimplemented");
     return false;
 }
@@ -603,8 +611,11 @@
     *static_cast<bool*>(userdata) = true;
 }
 
-bool GrDawnGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                             GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+bool GrDawnGpu::onReadPixels(GrSurface* surface,
+                             SkIRect rect,
+                             GrColorType surfaceColorType,
+                             GrColorType dstColorType,
+                             void* buffer,
                              size_t rowBytes) {
     wgpu::Texture tex = get_dawn_texture_from_surface(surface);
 
@@ -612,9 +623,9 @@
         return false;
     }
     size_t origRowBytes = rowBytes;
-    int origSizeInBytes = origRowBytes * height;
+    int origSizeInBytes = origRowBytes*rect.height();
     rowBytes = GrDawnRoundRowBytes(rowBytes);
-    int sizeInBytes = rowBytes * height;
+    int sizeInBytes = rowBytes*rect.height();
 
     wgpu::BufferDescriptor desc;
     desc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
@@ -624,15 +635,15 @@
 
     wgpu::ImageCopyTexture srcTexture;
     srcTexture.texture = tex;
-    srcTexture.origin = {(uint32_t) left, (uint32_t) top, 0};
+    srcTexture.origin = {(uint32_t) rect.left(), (uint32_t) rect.top(), 0};
 
     wgpu::ImageCopyBuffer dstBuffer = {};
     dstBuffer.buffer = buf;
     dstBuffer.layout.offset = 0;
     dstBuffer.layout.bytesPerRow = rowBytes;
-    dstBuffer.layout.rowsPerImage = height;
+    dstBuffer.layout.rowsPerImage = rect.height();
 
-    wgpu::Extent3D copySize = {(uint32_t) width, (uint32_t) height, 1};
+    wgpu::Extent3D copySize = {(uint32_t) rect.width(), (uint32_t) rect.height(), 1};
     this->getCopyEncoder().CopyTextureToBuffer(&srcTexture, &dstBuffer, &copySize);
     this->submitToGpu(true);
 
@@ -648,7 +659,7 @@
     } else {
         const char* src = static_cast<const char*>(readPixelsPtr);
         char* dst = static_cast<char*>(buffer);
-        for (int row = 0; row < height; row++) {
+        for (int row = 0; row < rect.height(); row++) {
             memcpy(dst, src, origRowBytes);
             dst += origRowBytes;
             src += rowBytes;
diff --git a/src/gpu/dawn/GrDawnGpu.h b/src/gpu/dawn/GrDawnGpu.h
index 389a90b..4ceaf3f 100644
--- a/src/gpu/dawn/GrDawnGpu.h
+++ b/src/gpu/dawn/GrDawnGpu.h
@@ -160,23 +160,35 @@
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType type, GrAccessPattern,
                                       const void* data) override;
 
-    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    bool onReadPixels(GrSurface*,
+                      SkIRect,
+                      GrColorType surfaceColorType,
+                      GrColorType dstColorType,
+                      void*,
                       size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType srcColorType,
-                       const GrMipLevel texels[], int mipLevelCount,
-                       bool prepForTexSampling) override;
+    bool onWritePixels(GrSurface*,
+                       SkIRect,
+                       GrColorType surfaceColorType,
+                       GrColorType srcColorType,
+                       const GrMipLevel[],
+                       int mipLevelCount,
+                       bool) override;
 
-    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
-                            GrColorType textureColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+    bool onTransferPixelsTo(GrTexture*,
+                            SkIRect,
+                            GrColorType textureColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer>,
+                            size_t offset,
                             size_t rowBytes) override;
 
-    bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType bufferColorType,
-                              sk_sp<GrGpuBuffer> transferBuffer, size_t offset) override;
+    bool onTransferPixelsFrom(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType bufferColorType,
+                              sk_sp<GrGpuBuffer>,
+                              size_t offset) override;
 
     void onResolveRenderTarget(GrRenderTarget*, const SkIRect&) override {}
 
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 3dfab74..1129476 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -815,9 +815,12 @@
     return true;
 }
 
-bool GrGLGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType srcColorType,
-                            const GrMipLevel texels[], int mipLevelCount,
+bool GrGLGpu::onWritePixels(GrSurface* surface,
+                            SkIRect rect,
+                            GrColorType surfaceColorType,
+                            GrColorType srcColorType,
+                            const GrMipLevel texels[],
+                            int mipLevelCount,
                             bool prepForTexSampling) {
     auto glTex = static_cast<GrGLTexture*>(surface->asTexture());
 
@@ -845,15 +848,22 @@
     }
 
     SkASSERT(!GrGLFormatIsCompressed(glTex->format()));
-    SkIRect dstRect = SkIRect::MakeXYWH(left, top, width, height);
-    return this->uploadColorTypeTexData(glTex->format(), surfaceColorType, glTex->dimensions(),
-                                        glTex->target(), dstRect, srcColorType, texels,
+    return this->uploadColorTypeTexData(glTex->format(),
+                                        surfaceColorType,
+                                        glTex->dimensions(),
+                                        glTex->target(),
+                                        rect,
+                                        srcColorType,
+                                        texels,
                                         mipLevelCount);
 }
 
-bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                 GrColorType textureColorType, GrColorType bufferColorType,
-                                 sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+bool GrGLGpu::onTransferPixelsTo(GrTexture* texture,
+                                 SkIRect rect,
+                                 GrColorType textureColorType,
+                                 GrColorType bufferColorType,
+                                 sk_sp<GrGpuBuffer> transferBuffer,
+                                 size_t offset,
                                  size_t rowBytes) {
     GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
 
@@ -865,9 +875,6 @@
     }
 
     static_assert(sizeof(int) == sizeof(int32_t), "");
-    if (width <= 0 || height <= 0) {
-        return false;
-    }
 
     this->bindTextureToScratchUnit(glTex->target(), glTex->textureID());
 
@@ -876,18 +883,11 @@
     const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(transferBuffer.get());
     this->bindBuffer(GrGpuBufferType::kXferCpuToGpu, glBuffer);
 
-    SkDEBUGCODE(
-        SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
-        SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
-        SkASSERT(bounds.contains(subRect));
-    )
+    SkASSERT(SkIRect::MakeSize(texture->dimensions()).contains(rect));
 
     size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
-    const size_t trimRowBytes = width * bpp;
+    const size_t trimRowBytes = rect.width() * bpp;
     const void* pixels = (void*)offset;
-    if (width < 0 || height < 0) {
-        return false;
-    }
 
     bool restoreGLRowLength = false;
     if (trimRowBytes != rowBytes) {
@@ -910,10 +910,12 @@
     GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
     GL_CALL(TexSubImage2D(glTex->target(),
                           0,
-                          left, top,
-                          width,
-                          height,
-                          externalFormat, externalType,
+                          rect.left(),
+                          rect.top(),
+                          rect.width(),
+                          rect.height(),
+                          externalFormat,
+                          externalType,
                           pixels));
 
     if (restoreGLRowLength) {
@@ -923,14 +925,21 @@
     return true;
 }
 
-bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                   GrColorType surfaceColorType, GrColorType dstColorType,
-                                   sk_sp<GrGpuBuffer> transferBuffer, size_t offset) {
+bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface,
+                                   SkIRect rect,
+                                   GrColorType surfaceColorType,
+                                   GrColorType dstColorType,
+                                   sk_sp<GrGpuBuffer> transferBuffer,
+                                   size_t offset) {
     auto* glBuffer = static_cast<GrGLBuffer*>(transferBuffer.get());
     this->bindBuffer(GrGpuBufferType::kXferGpuToCpu, glBuffer);
     auto offsetAsPtr = reinterpret_cast<void*>(offset);
-    return this->readOrTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
-                                          dstColorType, offsetAsPtr, width);
+    return this->readOrTransferPixelsFrom(surface,
+                                          rect,
+                                          surfaceColorType,
+                                          dstColorType,
+                                          offsetAsPtr,
+                                          rect.width());
 }
 
 void GrGLGpu::unbindXferBuffer(GrGpuBufferType type) {
@@ -2098,9 +2107,12 @@
     fHWStencilSettings.invalidate();
 }
 
-bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                       GrColorType surfaceColorType, GrColorType dstColorType,
-                                       void* offsetOrPtr, int rowWidthInPixels) {
+bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface,
+                                       SkIRect rect,
+                                       GrColorType surfaceColorType,
+                                       GrColorType dstColorType,
+                                       void* offsetOrPtr,
+                                       int rowWidthInPixels) {
     SkASSERT(surface);
 
     auto format = surface->backendFormat().asGLFormat();
@@ -2132,20 +2144,22 @@
         fHWBoundRenderTargetUniqueID.makeInvalid();
     }
 
-    // the read rect is viewport-relative
-    GrNativeRect readRect = {left, top, width, height};
-
     // determine if GL can read using the passed rowBytes or if we need a scratch buffer.
-    if (rowWidthInPixels != width) {
+    if (rowWidthInPixels != rect.width()) {
         SkASSERT(this->glCaps().readPixelsRowBytesSupport());
         GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowWidthInPixels));
     }
     GL_CALL(PixelStorei(GR_GL_PACK_ALIGNMENT, 1));
 
-    GL_CALL(ReadPixels(readRect.fX, readRect.fY, readRect.fWidth, readRect.fHeight,
-                       externalFormat, externalType, offsetOrPtr));
+    GL_CALL(ReadPixels(rect.left(),
+                       rect.top(),
+                       rect.width(),
+                       rect.height(),
+                       externalFormat,
+                       externalType,
+                       offsetOrPtr));
 
-    if (rowWidthInPixels != width) {
+    if (rowWidthInPixels != rect.width()) {
         SkASSERT(this->glCaps().readPixelsRowBytesSupport());
         GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
     }
@@ -2156,8 +2170,11 @@
     return true;
 }
 
-bool GrGLGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                           GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+bool GrGLGpu::onReadPixels(GrSurface* surface,
+                           SkIRect rect,
+                           GrColorType surfaceColorType,
+                           GrColorType dstColorType,
+                           void* buffer,
                            size_t rowBytes) {
     SkASSERT(surface);
 
@@ -2166,15 +2183,19 @@
     // GL_PACK_ROW_LENGTH is in terms of pixels not bytes.
     int rowPixelWidth;
 
-    if (rowBytes == SkToSizeT(width * bytesPerPixel)) {
-        rowPixelWidth = width;
+    if (rowBytes == SkToSizeT(rect.width()*bytesPerPixel)) {
+        rowPixelWidth = rect.width();
     } else {
         SkASSERT(!(rowBytes % bytesPerPixel));
         rowPixelWidth = rowBytes / bytesPerPixel;
     }
     this->unbindXferBuffer(GrGpuBufferType::kXferGpuToCpu);
-    return this->readOrTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
-                                          dstColorType, buffer, rowPixelWidth);
+    return this->readOrTransferPixelsFrom(surface,
+                                          rect,
+                                          surfaceColorType,
+                                          dstColorType,
+                                          buffer,
+                                          rowPixelWidth);
 }
 
 GrOpsRenderPass* GrGLGpu::onGetOpsRenderPass(
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 79d8d3e..4bc691a 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -295,25 +295,42 @@
                                        GrMipmapped,
                                        GrGLTextureParameters::SamplerOverriddenState*);
 
-    bool onReadPixels(GrSurface*, int left, int top, int width, int height,
-                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    bool onReadPixels(GrSurface*,
+                      SkIRect,
+                      GrColorType surfaceColorType,
+                      GrColorType dstColorType,
+                      void*,
                       size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface*, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType srcColorType,
-                       const GrMipLevel texels[], int mipLevelCount,
+    bool onWritePixels(GrSurface*,
+                       SkIRect,
+                       GrColorType surfaceColorType,
+                       GrColorType srcColorType,
+                       const GrMipLevel[],
+                       int mipLevelCount,
                        bool prepForTexSampling) override;
 
-    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
-                            GrColorType textureColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+    bool onTransferPixelsTo(GrTexture*,
+                            SkIRect,
+                            GrColorType textureColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer>,
+                            size_t offset,
                             size_t rowBytes) override;
-    bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType bufferColorType,
-                              sk_sp<GrGpuBuffer> transferBuffer, size_t offset) override;
-    bool readOrTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
-                                  GrColorType surfaceColorType, GrColorType dstColorType,
-                                  void* offsetOrPtr, int rowWidthInPixels);
+
+    bool onTransferPixelsFrom(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType bufferColorType,
+                              sk_sp<GrGpuBuffer>,
+                              size_t offset) override;
+
+    bool readOrTransferPixelsFrom(GrSurface*,
+                                  SkIRect rect,
+                                  GrColorType surfaceColorType,
+                                  GrColorType dstColorType,
+                                  void* offsetOrPtr,
+                                  int rowWidthInPixels);
 
     // Unbinds xfer buffers from GL for operations that don't need them.
     // Before calling any variation of TexImage, TexSubImage, etc..., call this with
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index a85d3d9..167632a 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -90,30 +90,44 @@
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t sizeInBytes, GrGpuBufferType, GrAccessPattern,
                                       const void*) override;
 
-    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    bool onReadPixels(GrSurface*,
+                      SkIRect,
+                      GrColorType surfaceColorType,
+                      GrColorType dstColorType,
+                      void*,
                       size_t rowBytes) override {
         return true;
     }
 
-    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType srcColorType,
-                       const GrMipLevel texels[], int mipLevelCount,
+    bool onWritePixels(GrSurface*,
+                       SkIRect,
+                       GrColorType surfaceColorType,
+                       GrColorType srcColorType,
+                       const GrMipLevel[],
+                       int mipLevelCount,
                        bool prepForTexSampling) override {
         return true;
     }
 
-    bool onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+    bool onTransferPixelsTo(GrTexture*,
+                            SkIRect,
+                            GrColorType surfaceColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer>,
+                            size_t offset,
                             size_t rowBytes) override {
         return true;
     }
-    bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType bufferColorType,
-                              sk_sp<GrGpuBuffer> transferBuffer, size_t offset) override {
+
+    bool onTransferPixelsFrom(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType bufferColorType,
+                              sk_sp<GrGpuBuffer>,
+                              size_t offset) override {
         return true;
     }
+
     bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
                        const SkIPoint& dstPoint) override {
         return true;
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 6de43fe..1f691f0 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -179,21 +179,35 @@
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t, GrGpuBufferType, GrAccessPattern,
                                       const void*) override;
 
-    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                      GrColorType surfaceColorType, GrColorType bufferColorType, void* buffer,
+    bool onReadPixels(GrSurface* surface,
+                      SkIRect,
+                      GrColorType surfaceColorType,
+                      GrColorType bufferColorType,
+                      void*,
                       size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface*, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType bufferColorType,
-                       const GrMipLevel[], int mipLevelCount,
+    bool onWritePixels(GrSurface*,
+                       SkIRect,
+                       GrColorType surfaceColorType,
+                       GrColorType bufferColorType,
+                       const GrMipLevel[],
+                       int mipLevelCount,
                        bool prepForTexSampling) override;
 
-    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
-                            GrColorType textureColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer>, size_t offset, size_t rowBytes) override;
-    bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType bufferColorType,
-                              sk_sp<GrGpuBuffer>, size_t offset) override;
+    bool onTransferPixelsTo(GrTexture*,
+                            SkIRect,
+                            GrColorType textureColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer>,
+                            size_t offset,
+                            size_t rowBytes) override;
+
+    bool onTransferPixelsFrom(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType bufferColorType,
+                              sk_sp<GrGpuBuffer>,
+                              size_t offset) override;
 
     bool onRegenerateMipMapLevels(GrTexture*) override;
 
@@ -225,13 +239,22 @@
     void checkForFinishedCommandBuffers();
 
     // Function that uploads data onto textures with private storage mode (GPU access only).
-    bool uploadToTexture(GrMtlTexture* tex, int left, int top, int width, int height,
-                         GrColorType dataColorType, const GrMipLevel texels[], int mipLevels);
+    bool uploadToTexture(GrMtlTexture* tex,
+                         SkIRect rect,
+                         GrColorType dataColorType,
+                         const GrMipLevel texels[],
+                         int mipLevels);
+
     // Function that fills texture levels with transparent black based on levelMask.
     bool clearTexture(GrMtlTexture*, size_t bbp, uint32_t levelMask);
-    bool readOrTransferPixels(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType dstColorType, id<MTLBuffer> transferBuffer, size_t offset,
-                              size_t imageBytes, size_t rowBytes);
+
+    bool readOrTransferPixels(GrSurface* surface,
+                              SkIRect rect,
+                              GrColorType dstColorType,
+                              id<MTLBuffer> transferBuffer,
+                              size_t offset,
+                              size_t imageBytes,
+                              size_t rowBytes);
 
     sk_sp<GrAttachment> makeStencilAttachment(const GrBackendFormat& /*colorFormat*/,
                                               SkISize dimensions, int numStencilSamples) override;
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index c44cdf9..7a5b762 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -340,22 +340,23 @@
     return true;
 }
 
-bool GrMtlGpu::uploadToTexture(GrMtlTexture* tex, int left, int top, int width, int height,
-                               GrColorType dataColorType, const GrMipLevel texels[],
+bool GrMtlGpu::uploadToTexture(GrMtlTexture* tex,
+                               SkIRect rect,
+                               GrColorType dataColorType,
+                               const GrMipLevel texels[],
                                int mipLevelCount) {
     SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
-    SkASSERT(1 == mipLevelCount ||
-             (0 == left && 0 == top && width == tex->width() && height == tex->height()));
+    SkASSERT(mipLevelCount == 1 || rect == SkIRect::MakeSize(tex->dimensions()));
 
     // We assume that if the texture has mip levels, we either upload to all the levels or just the
     // first.
-    SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->maxMipmapLevel() + 1));
+    SkASSERT(mipLevelCount == 1 || mipLevelCount == (tex->maxMipmapLevel() + 1));
 
-    if (!check_max_blit_width(width)) {
+    if (!check_max_blit_width(rect.width())) {
         return false;
     }
-    if (width == 0 || height == 0) {
+    if (rect.isEmpty()) {
         return false;
     }
 
@@ -367,7 +368,7 @@
     // Either upload only the first miplevel or all miplevels
     SkASSERT(1 == mipLevelCount || mipLevelCount == (int)mtlTexture.mipmapLevelCount);
 
-    if (1 == mipLevelCount && !texels[0].fPixels) {
+    if (mipLevelCount == 1 && !texels[0].fPixels) {
         return true;   // no data to upload
     }
 
@@ -381,8 +382,10 @@
     size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
 
     SkTArray<size_t> individualMipOffsets(mipLevelCount);
-    size_t combinedBufferSize = GrComputeTightCombinedBufferSize(
-            bpp, {width, height}, &individualMipOffsets, mipLevelCount);
+    size_t combinedBufferSize = GrComputeTightCombinedBufferSize(bpp,
+                                                                 rect.size(),
+                                                                 &individualMipOffsets,
+                                                                 mipLevelCount);
     SkASSERT(combinedBufferSize);
 
 
@@ -401,10 +404,10 @@
     char* bufferData = (char*)slice.fOffsetMapPtr;
     GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
 
-    int currentWidth = width;
-    int currentHeight = height;
+    int currentWidth = rect.width();
+    int currentHeight = rect.height();
     int layerHeight = tex->height();
-    MTLOrigin origin = MTLOriginMake(left, top, 0);
+    MTLOrigin origin = MTLOriginMake(rect.left(), rect.top(), 0);
 
     auto cmdBuffer = this->commandBuffer();
     id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
@@ -1258,9 +1261,12 @@
     return success;
 }
 
-bool GrMtlGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                             GrColorType surfaceColorType, GrColorType srcColorType,
-                             const GrMipLevel texels[], int mipLevelCount,
+bool GrMtlGpu::onWritePixels(GrSurface* surface,
+                             SkIRect rect,
+                             GrColorType surfaceColorType,
+                             GrColorType srcColorType,
+                             const GrMipLevel texels[],
+                             int mipLevelCount,
                              bool prepForTexSampling) {
     GrMtlTexture* mtlTexture = static_cast<GrMtlTexture*>(surface->asTexture());
     // TODO: In principle we should be able to support pure rendertargets as well, but
@@ -1276,12 +1282,14 @@
         SkASSERT(texels[i].fPixels);
     }
 #endif
-    return this->uploadToTexture(mtlTexture, left, top, width, height, srcColorType, texels,
-                                 mipLevelCount);
+    return this->uploadToTexture(mtlTexture, rect, srcColorType, texels, mipLevelCount);
 }
 
-bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+bool GrMtlGpu::onReadPixels(GrSurface* surface,
+                            SkIRect rect,
+                            GrColorType surfaceColorType,
+                            GrColorType dstColorType,
+                            void* buffer,
                             size_t rowBytes) {
     SkASSERT(surface);
 
@@ -1290,8 +1298,8 @@
     }
 
     int bpp = GrColorTypeBytesPerPixel(dstColorType);
-    size_t transBufferRowBytes = bpp * width;
-    size_t transBufferImageBytes = transBufferRowBytes * height;
+    size_t transBufferRowBytes = bpp*rect.width();
+    size_t transBufferImageBytes = transBufferRowBytes*rect.height();
 
     // TODO: implement some way of reusing buffers instead of making a new one every time.
     NSUInteger options = 0;
@@ -1313,23 +1321,35 @@
     }
 
     GrMtlBuffer* grMtlBuffer = static_cast<GrMtlBuffer*>(transferBuffer.get());
-    if (!this->readOrTransferPixels(surface, left, top, width, height, dstColorType,
+    if (!this->readOrTransferPixels(surface,
+                                    rect,
+                                    dstColorType,
                                     grMtlBuffer->mtlBuffer(),
-                                    0, transBufferImageBytes, transBufferRowBytes)) {
+                                    0,
+                                    transBufferImageBytes,
+                                    transBufferRowBytes)) {
         return false;
     }
     this->submitCommandBuffer(kForce_SyncQueue);
 
     const void* mappedMemory = grMtlBuffer->mtlBuffer().contents;
 
-    SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, transBufferRowBytes, height);
+    SkRectMemcpy(buffer,
+                 rowBytes,
+                 mappedMemory,
+                 transBufferRowBytes,
+                 transBufferRowBytes,
+                 rect.height());
 
     return true;
 }
 
-bool GrMtlGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                  GrColorType textureColorType, GrColorType bufferColorType,
-                                  sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+bool GrMtlGpu::onTransferPixelsTo(GrTexture* texture,
+                                  SkIRect rect,
+                                  GrColorType textureColorType,
+                                  GrColorType bufferColorType,
+                                  sk_sp<GrGpuBuffer> transferBuffer,
+                                  size_t offset,
                                   size_t rowBytes) {
     SkASSERT(texture);
     SkASSERT(transferBuffer);
@@ -1353,15 +1373,15 @@
         return false;
     }
 
-    MTLOrigin origin = MTLOriginMake(left, top, 0);
+    MTLOrigin origin = MTLOriginMake(rect.left(), rect.top(), 0);
 
     auto cmdBuffer = this->commandBuffer();
     id<MTLBlitCommandEncoder> GR_NORETAIN blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
     [blitCmdEncoder copyFromBuffer: mtlBuffer
                       sourceOffset: offset + grMtlBuffer->offset()
                  sourceBytesPerRow: rowBytes
-               sourceBytesPerImage: rowBytes*height
-                        sourceSize: MTLSizeMake(width, height, 1)
+               sourceBytesPerImage: rowBytes*rect.height()
+                        sourceSize: MTLSizeMake(rect.width(), rect.height(), 1)
                          toTexture: mtlTexture
                   destinationSlice: 0
                   destinationLevel: 0
@@ -1370,9 +1390,12 @@
     return true;
 }
 
-bool GrMtlGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                    GrColorType surfaceColorType, GrColorType bufferColorType,
-                                    sk_sp<GrGpuBuffer> transferBuffer, size_t offset) {
+bool GrMtlGpu::onTransferPixelsFrom(GrSurface* surface,
+                                    SkIRect rect,
+                                    GrColorType surfaceColorType,
+                                    GrColorType bufferColorType,
+                                    sk_sp<GrGpuBuffer> transferBuffer,
+                                    size_t offset) {
     SkASSERT(surface);
     SkASSERT(transferBuffer);
 
@@ -1391,18 +1414,26 @@
 
     GrMtlBuffer* grMtlBuffer = static_cast<GrMtlBuffer*>(transferBuffer.get());
 
-    size_t transBufferRowBytes = bpp * width;
-    size_t transBufferImageBytes = transBufferRowBytes * height;
+    size_t transBufferRowBytes = bpp*rect.width();
+    size_t transBufferImageBytes = transBufferRowBytes*rect.height();
 
-    return this->readOrTransferPixels(surface, left, top, width, height, bufferColorType,
-                                      grMtlBuffer->mtlBuffer(), offset + grMtlBuffer->offset(),
-                                      transBufferImageBytes, transBufferRowBytes);
+    return this->readOrTransferPixels(surface,
+                                      rect,
+                                      bufferColorType,
+                                      grMtlBuffer->mtlBuffer(),
+                                      offset + grMtlBuffer->offset(),
+                                      transBufferImageBytes,
+                                      transBufferRowBytes);
 }
 
-bool GrMtlGpu::readOrTransferPixels(GrSurface* surface, int left, int top, int width, int height,
-                                    GrColorType dstColorType, id<MTLBuffer> transferBuffer,
-                                    size_t offset, size_t imageBytes, size_t rowBytes) {
-    if (!check_max_blit_width(width)) {
+bool GrMtlGpu::readOrTransferPixels(GrSurface* surface,
+                                    SkIRect rect,
+                                    GrColorType dstColorType,
+                                    id<MTLBuffer> transferBuffer,
+                                    size_t offset,
+                                    size_t imageBytes,
+                                    size_t rowBytes) {
+    if (!check_max_blit_width(rect.width())) {
         return false;
     }
 
@@ -1427,8 +1458,8 @@
     [blitCmdEncoder copyFromTexture: mtlTexture
                         sourceSlice: 0
                         sourceLevel: 0
-                       sourceOrigin: MTLOriginMake(left, top, 0)
-                         sourceSize: MTLSizeMake(width, height, 1)
+                       sourceOrigin: MTLOriginMake(rect.left(), rect.top(), 0)
+                         sourceSize: MTLSizeMake(rect.width(), rect.height(), 1)
                            toBuffer: transferBuffer
                   destinationOffset: offset
              destinationBytesPerRow: rowBytes
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index cea30b0..b0f1b90 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -475,9 +475,12 @@
     return buff;
 }
 
-bool GrVkGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType surfaceColorType, GrColorType srcColorType,
-                            const GrMipLevel texels[], int mipLevelCount,
+bool GrVkGpu::onWritePixels(GrSurface* surface,
+                            SkIRect rect,
+                            GrColorType surfaceColorType,
+                            GrColorType srcColorType,
+                            const GrMipLevel texels[],
+                            int mipLevelCount,
                             bool prepForTexSampling) {
     GrVkTexture* texture = static_cast<GrVkTexture*>(surface->asTexture());
     if (!texture) {
@@ -509,12 +512,18 @@
                 return false;
             }
         }
-        success = this->uploadTexDataLinear(texAttachment, left, top, width, height, srcColorType,
-                                            texels[0].fPixels, texels[0].fRowBytes);
+        success = this->uploadTexDataLinear(texAttachment,
+                                            rect,
+                                            srcColorType,
+                                            texels[0].fPixels,
+                                            texels[0].fRowBytes);
     } else {
         SkASSERT(mipLevelCount <= (int)texAttachment->mipLevels());
-        success = this->uploadTexDataOptimal(texAttachment, left, top, width, height, srcColorType,
-                                             texels, mipLevelCount);
+        success = this->uploadTexDataOptimal(texAttachment,
+                                             rect,
+                                             srcColorType,
+                                             texels,
+                                             mipLevelCount);
         if (1 == mipLevelCount) {
             texture->markMipmapsDirty();
         }
@@ -531,9 +540,12 @@
     return success;
 }
 
-bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                 GrColorType surfaceColorType, GrColorType bufferColorType,
-                                 sk_sp<GrGpuBuffer> transferBuffer, size_t bufferOffset,
+bool GrVkGpu::onTransferPixelsTo(GrTexture* texture,
+                                 SkIRect rect,
+                                 GrColorType surfaceColorType,
+                                 GrColorType bufferColorType,
+                                 sk_sp<GrGpuBuffer> transferBuffer,
+                                 size_t bufferOffset,
                                  size_t rowBytes) {
     if (!this->currentCommandBuffer()) {
         return false;
@@ -567,11 +579,7 @@
     }
     SkASSERT(GrVkFormatBytesPerBlock(format) == GrColorTypeBytesPerPixel(bufferColorType));
 
-    SkDEBUGCODE(
-        SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
-        SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
-        SkASSERT(bounds.contains(subRect));
-    )
+    SkASSERT(SkIRect::MakeSize(texture->dimensions()).contains(rect));
 
     // Set up copy region
     VkBufferImageCopy region;
@@ -580,8 +588,8 @@
     region.bufferRowLength = (uint32_t)(rowBytes/bpp);
     region.bufferImageHeight = 0;
     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
-    region.imageOffset = { left, top, 0 };
-    region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
+    region.imageOffset = { rect.left(), rect.top(), 0 };
+    region.imageExtent = { (uint32_t)rect.width(), (uint32_t)rect.height(), 1 };
 
     // Change layout of our target so it can be copied to
     vkTex->setImageLayout(this,
@@ -605,9 +613,12 @@
     return true;
 }
 
-bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                   GrColorType surfaceColorType, GrColorType bufferColorType,
-                                   sk_sp<GrGpuBuffer> transferBuffer, size_t offset) {
+bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface,
+                                   SkIRect rect,
+                                   GrColorType surfaceColorType,
+                                   GrColorType bufferColorType,
+                                   sk_sp<GrGpuBuffer> transferBuffer,
+                                   size_t offset) {
     if (!this->currentCommandBuffer()) {
         return false;
     }
@@ -644,11 +655,11 @@
     VkBufferImageCopy region;
     memset(&region, 0, sizeof(VkBufferImageCopy));
     region.bufferOffset = offset;
-    region.bufferRowLength = width;
+    region.bufferRowLength = rect.width();
     region.bufferImageHeight = 0;
     region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
-    region.imageOffset = { left, top, 0 };
-    region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
+    region.imageOffset = {rect.left(), rect.top(), 0};
+    region.imageExtent = {(uint32_t)rect.width(), (uint32_t)rect.height(), 1};
 
     srcImage->setImageLayout(this,
                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
@@ -729,19 +740,18 @@
                        SkIPoint::Make(resolveRect.x(), resolveRect.y()));
 }
 
-bool GrVkGpu::uploadTexDataLinear(GrVkAttachment* texAttachment, int left, int top, int width,
-                                  int height, GrColorType dataColorType, const void* data,
+bool GrVkGpu::uploadTexDataLinear(GrVkAttachment* texAttachment,
+                                  SkIRect rect,
+                                  GrColorType dataColorType,
+                                  const void* data,
                                   size_t rowBytes) {
     SkASSERT(data);
     SkASSERT(texAttachment->isLinearTiled());
 
-    SkDEBUGCODE(
-        SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
-        SkIRect bounds = SkIRect::MakeWH(texAttachment->width(), texAttachment->height());
-        SkASSERT(bounds.contains(subRect));
-    )
+    SkASSERT(SkIRect::MakeSize(texAttachment->dimensions()).contains(rect));
+
     size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
-    size_t trimRowBytes = width * bpp;
+    size_t trimRowBytes = rect.width() * bpp;
 
     SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == texAttachment->currentLayout() ||
              VK_IMAGE_LAYOUT_GENERAL == texAttachment->currentLayout());
@@ -763,8 +773,8 @@
     if (VK_NULL_HANDLE == alloc.fMemory) {
         return false;
     }
-    VkDeviceSize offset = top * layout.rowPitch + left * bpp;
-    VkDeviceSize size = height*layout.rowPitch;
+    VkDeviceSize offset = rect.top()*layout.rowPitch + rect.left()*bpp;
+    VkDeviceSize size = rect.height()*layout.rowPitch;
     SkASSERT(size + offset <= alloc.fSize);
     void* mapPtr = GrVkMemory::MapAlloc(this, alloc);
     if (!mapPtr) {
@@ -772,8 +782,12 @@
     }
     mapPtr = reinterpret_cast<char*>(mapPtr) + offset;
 
-    SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), data, rowBytes, trimRowBytes,
-                 height);
+    SkRectMemcpy(mapPtr,
+                 static_cast<size_t>(layout.rowPitch),
+                 data,
+                 rowBytes,
+                 trimRowBytes,
+                 rect.height());
 
     GrVkMemory::FlushMappedAlloc(this, alloc, offset, size);
     GrVkMemory::UnmapAlloc(this, alloc);
@@ -840,8 +854,10 @@
     return bufferSize;
 }
 
-bool GrVkGpu::uploadTexDataOptimal(GrVkAttachment* texAttachment, int left, int top, int width,
-                                   int height, GrColorType dataColorType, const GrMipLevel texels[],
+bool GrVkGpu::uploadTexDataOptimal(GrVkAttachment* texAttachment,
+                                   SkIRect rect,
+                                   GrColorType dataColorType,
+                                   const GrMipLevel texels[],
                                    int mipLevelCount) {
     if (!this->currentCommandBuffer()) {
         return false;
@@ -849,17 +865,13 @@
 
     SkASSERT(!texAttachment->isLinearTiled());
     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
-    SkASSERT(1 == mipLevelCount ||
-             (0 == left && 0 == top && width == texAttachment->width() &&
-              height == texAttachment->height()));
+    SkASSERT(mipLevelCount == 1 || rect == SkIRect::MakeSize(texAttachment->dimensions()));
 
     // We assume that if the texture has mip levels, we either upload to all the levels or just the
     // first.
-    SkASSERT(1 == mipLevelCount || mipLevelCount == (int)texAttachment->mipLevels());
+    SkASSERT(mipLevelCount == 1 || mipLevelCount == (int)texAttachment->mipLevels());
 
-    if (width == 0 || height == 0) {
-        return false;
-    }
+    SkASSERT(!rect.isEmpty());
 
     SkASSERT(this->vkCaps().surfaceSupportsWritePixels(texAttachment));
 
@@ -876,12 +888,12 @@
     size_t combinedBufferSize;
     if (mipLevelCount > 1) {
         combinedBufferSize = GrComputeTightCombinedBufferSize(bpp,
-                                                              {width, height},
+                                                              rect.size(),
                                                               &individualMipOffsets,
                                                               mipLevelCount);
     } else {
         SkASSERT(texelsShallowCopy[0].fPixels && texelsShallowCopy[0].fRowBytes);
-        combinedBufferSize = width*height*bpp;
+        combinedBufferSize = rect.width()*rect.height()*bpp;
         individualMipOffsets.push_back(0);
     }
     SkASSERT(combinedBufferSize);
@@ -900,14 +912,14 @@
         return false;
     }
 
-    int uploadLeft = left;
-    int uploadTop = top;
+    int uploadLeft = rect.left();
+    int uploadTop = rect.top();
 
     char* buffer = (char*) slice.fOffsetMapPtr;
     SkTArray<VkBufferImageCopy> regions(mipLevelCount);
 
-    int currentWidth = width;
-    int currentHeight = height;
+    int currentWidth = rect.width();
+    int currentHeight = rect.height();
     int layerHeight = texAttachment->height();
     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
         if (texelsShallowCopy[currentMipLevel].fPixels) {
@@ -2330,8 +2342,11 @@
     return false;
 }
 
-bool GrVkGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                           GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+bool GrVkGpu::onReadPixels(GrSurface* surface,
+                           SkIRect rect,
+                           GrColorType surfaceColorType,
+                           GrColorType dstColorType,
+                           void* buffer,
                            size_t rowBytes) {
     if (surface->isProtected()) {
         return false;
@@ -2375,13 +2390,13 @@
     if (GrVkFormatBytesPerBlock(image->imageFormat()) != bpp) {
         return false;
     }
-    size_t tightRowBytes = bpp * width;
+    size_t tightRowBytes = bpp*rect.width();
 
     VkBufferImageCopy region;
     memset(&region, 0, sizeof(VkBufferImageCopy));
-    VkOffset3D offset = { left, top, 0 };
+    VkOffset3D offset = { rect.left(), rect.top(), 0 };
     region.imageOffset = offset;
-    region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
+    region.imageExtent = { (uint32_t)rect.width(), (uint32_t)rect.height(), 1 };
 
     size_t transBufferRowBytes = bpp * region.imageExtent.width;
     size_t imageRows = region.imageExtent.height;
@@ -2423,7 +2438,7 @@
     }
     void* mappedMemory = transferBuffer->map();
 
-    SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, height);
+    SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes, rect.height());
 
     transferBuffer->unmap();
     return true;
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 30a5edc..7ac6e39 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -268,22 +268,35 @@
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType type, GrAccessPattern,
                                       const void* data) override;
 
-    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+    bool onReadPixels(GrSurface*,
+                      SkIRect,
+                      GrColorType surfaceColorType,
+                      GrColorType dstColorType,
+                      void* buffer,
                       size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                       GrColorType surfaceColorType, GrColorType srcColorType,
-                       const GrMipLevel texels[], int mipLevelCount,
+    bool onWritePixels(GrSurface*,
+                       SkIRect,
+                       GrColorType surfaceColorType,
+                       GrColorType srcColorType,
+                       const GrMipLevel[],
+                       int mipLevelCount,
                        bool prepForTexSampling) override;
 
-    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
-                            GrColorType textureColorType, GrColorType bufferColorType,
-                            sk_sp<GrGpuBuffer> transferBuffer, size_t offset,
+    bool onTransferPixelsTo(GrTexture*,
+                            SkIRect,
+                            GrColorType textureColorType,
+                            GrColorType bufferColorType,
+                            sk_sp<GrGpuBuffer>,
+                            size_t offset,
                             size_t rowBytes) override;
-    bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType surfaceColorType, GrColorType bufferColorType,
-                              sk_sp<GrGpuBuffer> transferBuffer, size_t offset) override;
+
+    bool onTransferPixelsFrom(GrSurface*,
+                              SkIRect,
+                              GrColorType surfaceColorType,
+                              GrColorType bufferColorType,
+                              sk_sp<GrGpuBuffer>,
+                              size_t offset) override;
 
     bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
                        const SkIPoint& dstPoint) override;
@@ -331,10 +344,16 @@
                               const SkIPoint& dstPoint);
 
     // helpers for onCreateTexture and writeTexturePixels
-    bool uploadTexDataLinear(GrVkAttachment* tex, int left, int top, int width, int height,
-                             GrColorType colorType, const void* data, size_t rowBytes);
-    bool uploadTexDataOptimal(GrVkAttachment* tex, int left, int top, int width, int height,
-                              GrColorType colorType, const GrMipLevel texels[], int mipLevelCount);
+    bool uploadTexDataLinear(GrVkAttachment* tex,
+                             SkIRect rect,
+                             GrColorType colorType,
+                             const void* data,
+                             size_t rowBytes);
+    bool uploadTexDataOptimal(GrVkAttachment* tex,
+                              SkIRect rect,
+                              GrColorType colorType,
+                              const GrMipLevel texels[],
+                              int mipLevelCount);
     bool uploadTexDataCompressed(GrVkAttachment* tex, SkImage::CompressionType compression,
                                  VkFormat vkFormat, SkISize dimensions, GrMipmapped mipMapped,
                                  const void* data, size_t dataSize);
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index 79aae77..0f94d5e 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -389,9 +389,12 @@
         // Try the low level write.
         dContext->flushAndSubmit();
         auto gpuWriteResult = dContext->priv().getGpu()->writePixels(
-                proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888,
-                GrColorType::kRGBA_8888, write.addr32(),
-                kSize * GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
+                proxy->peekTexture(),
+                SkIRect::MakeWH(kSize, kSize),
+                GrColorType::kRGBA_8888,
+                GrColorType::kRGBA_8888,
+                write.addr32(),
+                kSize*GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
         REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
 
         SkBitmap copySrcBitmap;
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
index b832978..6b403ec 100644
--- a/tests/TransferPixelsTest.cpp
+++ b/tests/TransferPixelsTest.cpp
@@ -82,8 +82,12 @@
     if (supportedRead.fColorType != colorType) {
         size_t tmpRowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * w;
         std::unique_ptr<char[]> tmpPixels(new char[tmpRowBytes * h]);
-        if (!gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType,
-                             tmpPixels.get(), tmpRowBytes)) {
+        if (!gpu->readPixels(texture,
+                             SkIRect::MakeWH(w, h),
+                             colorType,
+                             supportedRead.fColorType,
+                             tmpPixels.get(),
+                             tmpRowBytes)) {
             return false;
         }
         GrImageInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
@@ -92,7 +96,12 @@
         return GrConvertPixels(GrPixmap(dstInfo,             dst,    rowBytes),
                                GrPixmap(tmpInfo, tmpPixels.get(), tmpRowBytes));
     }
-    return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes);
+    return gpu->readPixels(texture,
+                           SkIRect::MakeWH(w, h),
+                           colorType,
+                           supportedRead.fColorType,
+                           dst,
+                           rowBytes);
 }
 
 void basic_transfer_to_test(skiatest::Reporter* reporter,
@@ -170,8 +179,13 @@
     // transfer full data
 
     bool result;
-    result = gpu->transferPixelsTo(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight, colorType,
-                                   allowedSrc.fColorType, buffer, 0, srcRowBytes);
+    result = gpu->transferPixelsTo(tex.get(),
+                                   SkIRect::MakeSize(kTexDims),
+                                   colorType,
+                                   allowedSrc.fColorType,
+                                   buffer,
+                                   0,
+                                   srcRowBytes);
     REPORTER_ASSERT(reporter, result);
 
     size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTexDims.fWidth;
@@ -237,8 +251,13 @@
     memcpy(data, srcData.get(), size);
     buffer->unmap();
 
-    result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType,
-                                   allowedSrc.fColorType, buffer, offset, srcRowBytes);
+    result = gpu->transferPixelsTo(tex.get(),
+                                   SkIRect::MakeXYWH(left, top, width, height),
+                                   colorType,
+                                   allowedSrc.fColorType,
+                                   buffer,
+                                   offset,
+                                   srcRowBytes);
     if (!result) {
         ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
                static_cast<int>(colorType));
@@ -340,8 +359,12 @@
 
     //////////////////////////
     // transfer full data
-    bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight,
-                                          colorType, allowedRead.fColorType, buffer, 0);
+    bool result = gpu->transferPixelsFrom(tex.get(),
+                                          SkIRect::MakeSize(kTexDims),
+                                          colorType,
+                                          allowedRead.fColorType,
+                                          buffer,
+                                          0);
     if (!result) {
         ERRORF(reporter, "transferPixelsFrom failed.");
         return;
@@ -382,9 +405,13 @@
 
     ///////////////////////
     // Now test a partial read at an offset into the buffer.
-    result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
-                                     kPartialHeight, colorType, allowedRead.fColorType,
-                                     buffer, partialReadOffset);
+    result = gpu->transferPixelsFrom(
+            tex.get(),
+            SkIRect::MakeXYWH(kPartialLeft, kPartialTop, kPartialWidth, kPartialHeight),
+            colorType,
+            allowedRead.fColorType,
+            buffer,
+            partialReadOffset);
     if (!result) {
         ERRORF(reporter, "transferPixelsFrom failed.");
         return;