Make read/write/transfer pixels functions take surface color type

Bug: skia:6718
Change-Id: I9cac1b9dc8c04969719c79b7b7ce10c18fb428d4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/231563
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrDeferredUpload.h b/src/gpu/GrDeferredUpload.h
index f38ee7a..887f853 100644
--- a/src/gpu/GrDeferredUpload.h
+++ b/src/gpu/GrDeferredUpload.h
@@ -117,7 +117,7 @@
  */
 using GrDeferredTextureUploadWritePixelsFn =
         std::function<bool(GrTextureProxy*, int left, int top, int width, int height,
-                           GrColorType colorType, const void* buffer, size_t rowBytes)>;
+                           GrColorType srcColorType, const void* buffer, size_t rowBytes)>;
 
 /**
  * A deferred texture upload is simply a std::function that takes a
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index f2835f3..280885f 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -343,9 +343,11 @@
 }
 
 bool GrGpu::readPixels(GrSurface* surface, int left, int top, int width, int height,
-                       GrColorType dstColorType, void* buffer, size_t rowBytes) {
+                       GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                       size_t rowBytes) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
+    SkASSERT(this->caps()->isFormatTexturable(surfaceColorType, surface->backendFormat()));
 
     auto subRect = SkIRect::MakeXYWH(left, top, width, height);
     auto bounds  = SkIRect::MakeWH(surface->width(), surface->height());
@@ -373,13 +375,16 @@
 
     this->handleDirtyContext();
 
-    return this->onReadPixels(surface, left, top, width, height, dstColorType, buffer, rowBytes);
+    return this->onReadPixels(surface, left, top, width, height, surfaceColorType, dstColorType,
+                              buffer, rowBytes);
 }
 
 bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height,
-                        GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount) {
+                        GrColorType surfaceColorType, GrColorType srcColorType,
+                        const GrMipLevel texels[], int mipLevelCount) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
+    SkASSERT(this->caps()->isFormatTexturable(surfaceColorType, surface->backendFormat()));
 
     if (surface->readOnly()) {
         return false;
@@ -405,8 +410,8 @@
     }
 
     this->handleDirtyContext();
-    if (this->onWritePixels(surface, left, top, width, height, srcColorType, texels,
-                            mipLevelCount)) {
+    if (this->onWritePixels(surface, left, top, width, height, surfaceColorType, srcColorType,
+                            texels, mipLevelCount)) {
         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
         this->didWriteToSurface(surface, kTopLeft_GrSurfaceOrigin, &rect, mipLevelCount);
         fStats.incTextureUploads();
@@ -416,11 +421,12 @@
 }
 
 bool GrGpu::transferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                             GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
-                             size_t offset, size_t rowBytes) {
+                             GrColorType textureColorType, GrColorType bufferColorType,
+                             GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(texture);
     SkASSERT(transferBuffer);
+    SkASSERT(this->caps()->isFormatTexturable(textureColorType, texture->backendFormat()));
 
     if (texture->readOnly()) {
         return false;
@@ -448,8 +454,8 @@
     }
 
     this->handleDirtyContext();
-    if (this->onTransferPixelsTo(texture, left, top, width, height, bufferColorType, transferBuffer,
-                                 offset, rowBytes)) {
+    if (this->onTransferPixelsTo(texture, left, top, width, height, textureColorType,
+                                 bufferColorType, transferBuffer, offset, rowBytes)) {
         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
         this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect);
         fStats.incTransfersToTexture();
@@ -460,11 +466,13 @@
 }
 
 bool GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                               GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
-                               size_t offset) {
+                               GrColorType surfaceColorType, GrColorType bufferColorType,
+                               GrGpuBuffer* transferBuffer, size_t offset) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
     SkASSERT(transferBuffer);
+    SkASSERT(this->caps()->isFormatTexturable(surfaceColorType, surface->backendFormat()));
+
 #ifdef SK_DEBUG
     GrColorType surfCT = GrPixelConfigToColorType(surface->config());
     auto supportedRead = this->caps()->supportedReadPixelsColorType(surfCT,
@@ -482,8 +490,8 @@
     }
 
     this->handleDirtyContext();
-    if (this->onTransferPixelsFrom(surface, left, top, width, height, bufferColorType,
-                                   transferBuffer, offset)) {
+    if (this->onTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
+                                   bufferColorType, transferBuffer, offset)) {
         fStats.incTransfersFromSurface();
         return true;
     }
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 4144cfb..fb9a7c5 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -182,18 +182,17 @@
     /**
      * 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 dstColorType  the color type of the destination buffer.
-     * @param buffer        memory to read the rectangle into.
-     * @param rowBytes      the number of bytes between consecutive rows. Must be a multiple of
-     *                      dstColorType's bytes-per-pixel. Must be tight to width if
-     *                      !caps->readPixelsRowBytesSupport().
-     * @param invertY       buffer should be populated bottom-to-top as opposed
-     *                      to top-to-bottom (skia's usual order)
+     * @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 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.
+     * @param rowBytes          the number of bytes between consecutive rows. Must be a multiple of
+     *                          dstColorType's bytes-per-pixel. Must be tight to width if
+     *                          !caps->readPixelsRowBytesSupport().
      *
      * @return true if the read succeeded, false if not. The read can fail
      *              because of the surface doesn't support reading, the color type
@@ -201,21 +200,23 @@
      *              read is not contained in the surface.
      */
     bool readPixels(GrSurface* surface, int left, int top, int width, int height,
-                    GrColorType dstColorType, void* buffer, size_t rowBytes);
+                    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 srcColorType  the color type of the source buffer.
-     * @param texels        array of mipmap levels containing texture data. Row bytes must be a
-     *                      multiple of srcColorType's bytes-per-pixel. Must be tight to level width
-     *                      if !caps->writePixelsRowBytesSupport().
-     * @param mipLevelCount number of levels in 'texels'
+     * @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 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
+     *                          multiple of srcColorType's bytes-per-pixel. Must be tight to level
+     *                          width if !caps->writePixelsRowBytesSupport().
+     * @param mipLevelCount     number of levels in 'texels'
      *
      * @return true if the write succeeded, false if not. The read can fail
      *              because of the surface doesn't support writing (e.g. read only),
@@ -223,15 +224,18 @@
      *              if the rectangle written is not contained in the surface.
      */
     bool writePixels(GrSurface* surface, int left, int top, int width, int height,
-                     GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount);
+                     GrColorType surfaceColorType, GrColorType srcColorType,
+                     const GrMipLevel texels[], int mipLevelCount);
 
     /**
      * Helper for the case of a single level.
      */
     bool writePixels(GrSurface* surface, int left, int top, int width, int height,
-                     GrColorType srcColorType, const void* buffer, size_t rowBytes) {
+                     GrColorType surfaceColorType, GrColorType srcColorType, const void* buffer,
+                     size_t rowBytes) {
         GrMipLevel mipLevel = {buffer, rowBytes};
-        return this->writePixels(surface, left, top, width, height, srcColorType, &mipLevel, 1);
+        return this->writePixels(surface, left, top, width, height, surfaceColorType, srcColorType,
+                                 &mipLevel, 1);
     }
 
     /**
@@ -243,6 +247,7 @@
      * @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 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
@@ -251,8 +256,8 @@
      *                         if !caps->writePixelsRowBytesSupport().
      */
     bool transferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                          GrColorType bufferColorType, GrGpuBuffer* transferBuffer, size_t offset,
-                          size_t rowBytes);
+                          GrColorType textureColorType, GrColorType bufferColorType,
+                          GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes);
 
     /**
      * Reads the pixels from a rectangle of a surface into a buffer. Use
@@ -270,14 +275,14 @@
      * @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 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 bufferColorType, GrGpuBuffer* transferBuffer,
-                            size_t offset);
-
+                            GrColorType surfaceColorType, GrColorType bufferColorType,
+                            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 the GrOpList level and this function implement faster copy paths. The rect
@@ -556,21 +561,24 @@
                                               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,
-                              void* buffer, size_t rowBytes) = 0;
+    virtual bool onReadPixels(GrSurface*, int left, int top, int width, int height,
+                              GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                              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,
+    virtual bool onWritePixels(GrSurface*, int left, int top, int width, int height,
+                               GrColorType surfaceColorType, GrColorType srcColorType,
                                const GrMipLevel texels[], int mipLevelCount) = 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 colorType, GrGpuBuffer* transferBuffer,
-                                    size_t offset, size_t rowBytes) = 0;
+                                    GrColorType textiueColorType, GrColorType bufferColorType,
+                                    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 colorType, GrGpuBuffer* transferBuffer,
-                                      size_t offset) = 0;
+                                      GrColorType surfaceColorType, GrColorType bufferColorType,
+                                      GrGpuBuffer* transferBuffer, size_t offset) = 0;
 
     // overridden by backend-specific derived class to perform the resolve
     virtual void onResolveRenderTarget(GrRenderTarget* target) = 0;
diff --git a/src/gpu/GrGpuCommandBuffer.h b/src/gpu/GrGpuCommandBuffer.h
index b73fd7d..401bcc9 100644
--- a/src/gpu/GrGpuCommandBuffer.h
+++ b/src/gpu/GrGpuCommandBuffer.h
@@ -34,8 +34,9 @@
     // already been adjusted for any origin flips.
     virtual void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) = 0;
     // Initiates a transfer from the surface owned by the command buffer to the GrGpuBuffer.
-    virtual void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                              GrGpuBuffer* transferBuffer, size_t offset) = 0;
+    virtual void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                              GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                              size_t offset) = 0;
 
     virtual void insertEventMarker(const char*) = 0;
 
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index 3fb6d50..1dcd544 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -88,35 +88,33 @@
 
 void GrOpFlushState::doUpload(GrDeferredTextureUploadFn& upload) {
     GrDeferredTextureUploadWritePixelsFn wp = [this](GrTextureProxy* dstProxy, int left, int top,
-                                                     int width, int height,
-                                                     GrColorType srcColorType, const void* buffer,
-                                                     size_t rowBytes) {
+                                                     int width, int height, 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(dstSurface->config(), srcColorType);
+                fGpu->caps()->supportedWritePixelsColorType(dstSurface->config(), colorType);
         size_t tightRB = width * GrColorTypeBytesPerPixel(supportedWrite.fColorType);
         SkASSERT(rowBytes >= tightRB);
         std::unique_ptr<char[]> tmpPixels;
-        if (supportedWrite.fColorType != srcColorType ||
+        if (supportedWrite.fColorType != colorType ||
             (!fGpu->caps()->writePixelsRowBytesSupport() && rowBytes != tightRB)) {
             tmpPixels.reset(new char[height * tightRB]);
             // Use kUnpremul to ensure no alpha type conversions or clamping occur.
             static constexpr auto kAT = kUnpremul_SkAlphaType;
-            GrPixelInfo srcInfo(srcColorType, kAT, nullptr, width, height);
+            GrPixelInfo srcInfo(colorType, kAT, nullptr, width, height);
             GrPixelInfo tmpInfo(supportedWrite.fColorType, kAT, nullptr, width,
                                 height);
             if (!GrConvertPixels(tmpInfo, tmpPixels.get(), tightRB, srcInfo, buffer, rowBytes)) {
                 return false;
             }
-            srcColorType = supportedWrite.fColorType;
             rowBytes = tightRB;
             buffer = tmpPixels.get();
         }
-        return this->fGpu->writePixels(dstSurface, left, top, width, height, srcColorType, buffer,
-                                       rowBytes);
+        return this->fGpu->writePixels(dstSurface, left, top, width, height, colorType,
+                                       supportedWrite.fColorType, buffer, rowBytes);
     };
     upload(wp);
 }
diff --git a/src/gpu/GrOpList.h b/src/gpu/GrOpList.h
index 1e3375f..a16303b 100644
--- a/src/gpu/GrOpList.h
+++ b/src/gpu/GrOpList.h
@@ -45,6 +45,7 @@
 
     virtual void transferFrom(GrRecordingContext*,
                               const SkIRect& srcRect,
+                              GrColorType surfaceColorType,
                               GrColorType dstColorType,
                               sk_sp<GrGpuBuffer> dst,
                               size_t dstOffset) = 0;
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index 97f4478..cd94e9c 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -601,10 +601,12 @@
 
 void GrRenderTargetOpList::transferFrom(GrRecordingContext* context,
                                         const SkIRect& srcRect,
+                                        GrColorType surfaceColorType,
                                         GrColorType dstColorType,
                                         sk_sp<GrGpuBuffer> dst,
                                         size_t dstOffset) {
-    auto op = GrTransferFromOp::Make(context, srcRect, dstColorType, std::move(dst), dstOffset);
+    auto op = GrTransferFromOp::Make(context, srcRect, surfaceColorType, dstColorType,
+                                     std::move(dst), dstOffset);
     this->addOp(std::move(op), *context->priv().caps());
 }
 
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index 260b32e..6106c76 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -112,6 +112,7 @@
 
     void transferFrom(GrRecordingContext*,
                       const SkIRect& srcRect,
+                      GrColorType surfaceColorType,
                       GrColorType dstColorType,
                       sk_sp<GrGpuBuffer> dst,
                       size_t dstOffset) override;
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index f400e8a..51679b9 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -204,8 +204,8 @@
     direct->priv().flushSurface(srcProxy);
 
     if (!direct->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dstInfo.width(),
-                                             dstInfo.height(), supportedRead.fColorType, readDst,
-                                             readRB)) {
+                                             dstInfo.height(), this->colorSpaceInfo().colorType(),
+                                             supportedRead.fColorType, readDst, readRB)) {
         return false;
     }
 
@@ -396,8 +396,9 @@
     // TODO: should this policy decision just be moved into the drawing manager?
     direct->priv().flushSurface(caps->preferVRAMUseOverFlushes() ? dstProxy : nullptr);
 
-    return direct->priv().getGpu()->writePixels(dstSurface, pt.fX, pt.fY, srcInfo.width(),
-                                                srcInfo.height(), srcColorType, src, rowBytes);
+    return direct->priv().getGpu()->writePixels(
+            dstSurface, pt.fX, pt.fY, srcInfo.width(), srcInfo.height(),
+            this->colorSpaceInfo().colorType(), srcColorType, src, rowBytes);
 }
 
 bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
@@ -625,7 +626,8 @@
         srcRect = SkIRect::MakeLTRB(rect.fLeft, this->height() - rect.fBottom, rect.fRight,
                                     this->height() - rect.fTop);
     }
-    this->getOpList()->transferFrom(fContext, srcRect, supportedRead.fColorType, buffer, 0);
+    this->getOpList()->transferFrom(fContext, srcRect, this->colorSpaceInfo().colorType(),
+                                    supportedRead.fColorType, buffer, 0);
     PixelTransferResult result;
     result.fTransferBuffer = std::move(buffer);
     auto at = this->colorSpaceInfo().alphaType();
diff --git a/src/gpu/GrTextureOpList.cpp b/src/gpu/GrTextureOpList.cpp
index b58f735..7e4d6c3 100644
--- a/src/gpu/GrTextureOpList.cpp
+++ b/src/gpu/GrTextureOpList.cpp
@@ -174,10 +174,12 @@
 
 void GrTextureOpList::transferFrom(GrRecordingContext* context,
                                    const SkIRect& srcRect,
+                                   GrColorType surfaceColorType,
                                    GrColorType dstColorType,
                                    sk_sp<GrGpuBuffer> dst,
                                    size_t dstOffset) {
-    auto op = GrTransferFromOp::Make(context, srcRect, dstColorType, std::move(dst), dstOffset);
+    auto op = GrTransferFromOp::Make(context, srcRect, surfaceColorType, dstColorType,
+                                     std::move(dst), dstOffset);
     this->recordOp(std::move(op));
 }
 
diff --git a/src/gpu/GrTextureOpList.h b/src/gpu/GrTextureOpList.h
index 82d20e3..fbfc6e1 100644
--- a/src/gpu/GrTextureOpList.h
+++ b/src/gpu/GrTextureOpList.h
@@ -56,6 +56,7 @@
 
     void transferFrom(GrRecordingContext*,
                       const SkIRect& srcRect,
+                      GrColorType surfaceColorType,
                       GrColorType dstColorType,
                       sk_sp<GrGpuBuffer> dst,
                       size_t dstOffset) override;
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 6f591af..c78ad0f 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -112,6 +112,7 @@
     bool isFormatCompressed(const GrBackendFormat&) const override;
 
     bool isFormatTexturable(GrColorType, const GrBackendFormat&) const override;
+    bool isFormatTexturable(GrColorType, GrGLFormat) const;
 
     bool isConfigTexturable(GrPixelConfig config) const override {
         GrColorType ct = GrPixelConfigToColorType(config);
@@ -509,7 +510,6 @@
     SupportedRead onSupportedReadPixelsColorType(GrColorType, const GrBackendFormat&,
                                                  GrColorType) const override;
 
-    bool isFormatTexturable(GrColorType, GrGLFormat) const;
     bool formatSupportsTexStorage(GrGLFormat) const;
 
     int getRenderTargetSampleCount(int requestedCount, GrColorType, GrGLFormat) const;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 41febff..5ad9765 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -853,8 +853,8 @@
 }
 
 bool GrGLGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType srcColorType, const GrMipLevel texels[],
-                            int mipLevelCount) {
+                            GrColorType surfaceColorType, GrColorType srcColorType,
+                            const GrMipLevel texels[], int mipLevelCount) {
     auto glTex = static_cast<GrGLTexture*>(surface->asTexture());
 
     if (!check_write_and_transfer_input(glTex)) {
@@ -863,25 +863,16 @@
 
     this->bindTextureToScratchUnit(glTex->target(), glTex->textureID());
 
-    // No sRGB transformation occurs in uploadTexData. We choose to make the src config match the
-    // srgb-ness of the surface to avoid issues in ES2 where internal/external formats must match.
-    // When we're on ES2 and the dst is GL_SRGB_ALPHA by making the config be kSRGB_8888 we know
-    // that our caps will choose GL_SRGB_ALPHA as the external format, too. On ES3 or regular GL our
-    // caps knows to make the external format be GL_RGBA.
-    auto srcAsConfig = GrColorTypeToPixelConfig(srcColorType);
-
     SkASSERT(!GrPixelConfigIsCompressed(glTex->config()));
-    return this->uploadTexData(glTex->config(), glTex->width(), glTex->height(), glTex->target(),
-                               kWrite_UploadType, left, top, width, height, srcAsConfig, texels,
-                               mipLevelCount);
+    return this->uploadTexData(glTex->format(), surfaceColorType, glTex->config(), glTex->width(),
+                               glTex->height(), glTex->target(), kWrite_UploadType, left, top,
+                               width, height, srcColorType, texels, mipLevelCount);
 }
 
 bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                 GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
-                                 size_t offset, size_t rowBytes) {
+                                 GrColorType textureColorType, GrColorType bufferColorType,
+                                 GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) {
     GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
-    GrPixelConfig texConfig = glTex->config();
-    SkASSERT(this->caps()->isConfigTexturable(texConfig));
 
     // Can't transfer compressed data
     SkASSERT(!GrPixelConfigIsCompressed(glTex->config()));
@@ -924,7 +915,6 @@
     }
 
     GrGLFormat textureFormat = glTex->format();
-    GrColorType textureColorType = GrPixelConfigToColorType(texConfig);
     // Internal format comes from the texture desc.
     GrGLenum internalFormat;
     // External format and type come from the upload data.
@@ -953,13 +943,13 @@
 }
 
 bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                   GrColorType dstColorType, GrGpuBuffer* transferBuffer,
-                                   size_t offset) {
+                                   GrColorType surfaceColorType, GrColorType dstColorType,
+                                   GrGpuBuffer* transferBuffer, size_t offset) {
     auto* glBuffer = static_cast<GrGLBuffer*>(transferBuffer);
     this->bindBuffer(GrGpuBufferType::kXferGpuToCpu, glBuffer);
     auto offsetAsPtr = reinterpret_cast<void*>(offset);
-    return this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType,
-                                          offsetAsPtr, width);
+    return this->readOrTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
+                                          dstColorType, offsetAsPtr, width);
 }
 
 /**
@@ -1129,16 +1119,15 @@
     }
 }
 
-// TODO: Make this take a GrColorType instead of dataConfig. This requires updating GrGLCaps to
-// convert from GrColorType to externalFormat/externalType GLenum values.
-bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight, GrGLenum target,
-                            UploadType uploadType, int left, int top, int width, int height,
-                            GrPixelConfig dataConfig, const GrMipLevel texels[], int mipLevelCount,
-                            GrMipMapsStatus* mipMapsStatus) {
+bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType,
+                            GrPixelConfig textureConfig, int texWidth, int texHeight,
+                            GrGLenum target, UploadType uploadType, int left, int top, int width,
+                            int height, GrColorType srcColorType, const GrMipLevel texels[],
+                            int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
     // If we're uploading compressed data then we should be using uploadCompressedTexData
-    SkASSERT(!GrPixelConfigIsCompressed(dataConfig));
+    SkASSERT(!GrGLFormatIsCompressed(textureFormat));
 
-    SkASSERT(this->caps()->isConfigTexturable(texConfig));
+    SkASSERT(this->glCaps().isFormatTexturable(textureColorType, textureFormat));
     SkDEBUGCODE(
         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
         SkIRect bounds = SkIRect::MakeWH(texWidth, texHeight);
@@ -1152,27 +1141,25 @@
     const GrGLInterface* interface = this->glInterface();
     const GrGLCaps& caps = this->glCaps();
 
-    size_t bpp = GrBytesPerPixel(dataConfig);
+    size_t bpp = GrColorTypeBytesPerPixel(srcColorType);
 
     if (width == 0 || height == 0) {
         return false;
     }
 
-    GrGLFormat textureFormat = this->glCaps().pixelConfigToFormat(texConfig);
-    GrColorType textureColorType = GrPixelConfigToColorType(texConfig);
-    GrColorType dataColorType = GrPixelConfigToColorType(dataConfig);
     // Internal format comes from the texture desc.
     GrGLenum internalFormat;
     // External format and type come from the upload data.
     GrGLenum externalFormat;
     GrGLenum externalType;
-    this->glCaps().getTexImageFormats(textureFormat, textureColorType, dataColorType,
+    this->glCaps().getTexImageFormats(textureFormat, textureColorType, srcColorType,
                                       &internalFormat, &externalFormat, &externalType);
     if (!externalFormat || !externalType) {
         return false;
     }
-    // TexStorage requires a sized format, and internalFormat may or may not be
-    GrGLenum internalFormatForTexStorage = this->glCaps().configSizedInternalFormat(texConfig);
+
+    // TODO: Make this format based, possibly move to getTexImageFormats.
+    GrGLenum internalFormatForTexStorage = this->glCaps().configSizedInternalFormat(textureConfig);
 
     /*
      *  Check whether to allocate a temporary buffer for flipping y or
@@ -1198,7 +1185,7 @@
     if (kNewTexture_UploadType == uploadType) {
         if (0 == left && 0 == top && texWidth == width && texHeight == height) {
             succeeded = allocate_and_populate_texture(
-                    texConfig, *interface, caps, target, internalFormat,
+                    textureConfig, *interface, caps, target, internalFormat,
                     internalFormatForTexStorage, externalFormat, externalType, texels,
                     mipLevelCount, width, height, &restoreGLRowLength, mipMapsStatus);
         } else {
@@ -1698,9 +1685,13 @@
 
     *initialState = set_initial_texture_params(this->glInterface(), *info);
 
-    if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, info->fTarget,
-                             kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
-                             texels, mipLevelCount, mipMapsStatus)) {
+    auto format = GrGLFormatFromGLEnum(info->fFormat);
+    // TODO: Take these as parameters.
+    auto textureColorType = GrPixelConfigToColorType(desc.fConfig);
+    auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
+    if (!this->uploadTexData(format, textureColorType, desc.fConfig, desc.fWidth, desc.fHeight,
+                             info->fTarget, kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight,
+                             srcColorType, texels, mipLevelCount, mipMapsStatus)) {
         GL_CALL(DeleteTextures(1, &(info->fID)));
         return false;
     }
@@ -2160,10 +2151,9 @@
     fHWStencilSettings.invalidate();
 }
 
-
 bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                       GrColorType dstColorType, void* offsetOrPtr,
-                                       int rowWidthInPixels) {
+                                       GrColorType surfaceColorType, GrColorType dstColorType,
+                                       void* offsetOrPtr, int rowWidthInPixels) {
     SkASSERT(surface);
 
     GrGLRenderTarget* renderTarget = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
@@ -2172,7 +2162,6 @@
     }
 
     GrGLFormat surfaceFormat = GrGLBackendFormatToGLFormat(surface->backendFormat());
-    GrColorType surfaceColorType = GrPixelConfigToColorType(surface->config());
     GrGLenum externalFormat = 0;
     GrGLenum externalType = 0;
     this->glCaps().getReadPixelsFormat(surfaceFormat, surfaceColorType, dstColorType,
@@ -2247,7 +2236,8 @@
 }
 
 bool GrGLGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                           GrColorType dstColorType, void* buffer, size_t rowBytes) {
+                           GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                           size_t rowBytes) {
     SkASSERT(surface);
 
     size_t bytesPerPixel = GrColorTypeBytesPerPixel(dstColorType);
@@ -2261,8 +2251,8 @@
         SkASSERT(!(rowBytes % bytesPerPixel));
         rowPixelWidth = rowBytes / bytesPerPixel;
     }
-    return this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType, buffer,
-                                          rowPixelWidth);
+    return this->readOrTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
+                                          dstColorType, buffer, rowPixelWidth);
 }
 
 GrGpuRTCommandBuffer* GrGLGpu::getCommandBuffer(
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index e2ddf8d..19bb730 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -231,17 +231,22 @@
                                      GrGLTextureParameters::SamplerOverriddenState* initialState,
                                      const void* data);
 
-    bool onReadPixels(GrSurface*, int left, int top, int width, int height, GrColorType,
-                      void* buffer, size_t rowBytes) override;
+    bool onReadPixels(GrSurface*, int left, int top, int width, int height,
+                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                      size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface*, int left, int top, int width, int height, GrColorType,
+    bool onWritePixels(GrSurface*, int left, int top, int width, int height,
+                       GrColorType surfaceColorType, GrColorType srcColorType,
                        const GrMipLevel texels[], int mipLevelCount) override;
 
-    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height, GrColorType,
+    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
+                            GrColorType textureColorType, GrColorType bufferColorType,
                             GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) override;
-    bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
+    bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
+                              GrColorType surfaceColorType, GrColorType bufferColorType,
                               GrGpuBuffer* transferBuffer, size_t offset) override;
-    bool readOrTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
+    bool readOrTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
+                                  GrColorType surfaceColorType, GrColorType dstColorType,
                                   void* offsetOrPtr, int rowWidthInPixels);
 
     // Before calling any variation of TexImage, TexSubImage, etc..., call this to ensure that the
@@ -389,9 +394,10 @@
         kNewTexture_UploadType,   // we are creating a new texture
         kWrite_UploadType,        // we are using TexSubImage2D to copy data to an existing texture
     };
-    bool uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight, GrGLenum target,
+    bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType,
+                       GrPixelConfig textureConfig, int texWidth, int texHeight, GrGLenum target,
                        UploadType uploadType, int left, int top, int width, int height,
-                       GrPixelConfig dataConfig, const GrMipLevel texels[], int mipLevelCount,
+                       GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount,
                        GrMipMapsStatus* mipMapsStatus = nullptr);
 
     // Helper for onCreateCompressedTexture. Compressed textures are read-only so we
diff --git a/src/gpu/gl/GrGLGpuCommandBuffer.h b/src/gpu/gl/GrGLGpuCommandBuffer.h
index a67b41a..2a4d387 100644
--- a/src/gpu/gl/GrGLGpuCommandBuffer.h
+++ b/src/gpu/gl/GrGLGpuCommandBuffer.h
@@ -25,10 +25,12 @@
         fGpu->copySurface(fTexture, src, srcRect, dstPoint);
     }
 
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override {
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override {
         fGpu->transferPixelsFrom(fTexture, srcRect.fLeft, srcRect.fTop, srcRect.width(),
-                                 srcRect.height(), bufferColorType, transferBuffer, offset);
+                                 srcRect.height(), surfaceColorType, bufferColorType,
+                                 transferBuffer, offset);
     }
 
     void insertEventMarker(const char* msg) override {
@@ -69,10 +71,12 @@
         fGpu->copySurface(fRenderTarget, src,srcRect, dstPoint);
     }
 
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override {
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override {
         fGpu->transferPixelsFrom(fRenderTarget, srcRect.fLeft, srcRect.fTop, srcRect.width(),
-                                 srcRect.height(), bufferColorType, transferBuffer, offset);
+                                 srcRect.height(), surfaceColorType, bufferColorType,
+                                 transferBuffer, offset);
     }
 
     void set(GrRenderTarget*, GrSurfaceOrigin,
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 8b4d809..5d86a84 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -85,23 +85,26 @@
     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,
-                      void* buffer, size_t rowBytes) override {
+    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
+                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                      size_t rowBytes) override {
         return true;
     }
 
-    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height, GrColorType,
+    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height,
+                       GrColorType surfaceColorType, GrColorType srcColorType,
                        const GrMipLevel texels[], int mipLevelCount) override {
         return true;
     }
 
     bool onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                            GrColorType, GrGpuBuffer* transferBuffer, size_t offset,
-                            size_t rowBytes) override {
+                            GrColorType surfaceColorType, GrColorType bufferColorType,
+                            GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) override {
         return true;
     }
     bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override {
+                              GrColorType surfaceColorType, GrColorType bufferColorType,
+                              GrGpuBuffer* transferBuffer, size_t offset) override {
         return true;
     }
     bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
diff --git a/src/gpu/mock/GrMockGpuCommandBuffer.h b/src/gpu/mock/GrMockGpuCommandBuffer.h
index e1619af..aa75378 100644
--- a/src/gpu/mock/GrMockGpuCommandBuffer.h
+++ b/src/gpu/mock/GrMockGpuCommandBuffer.h
@@ -20,8 +20,9 @@
     ~GrMockGpuTextureCommandBuffer() override {}
 
     void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override {}
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override {}
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override {}
     void insertEventMarker(const char*) override {}
 
 private:
@@ -41,8 +42,9 @@
     void begin() override {}
     void end() override {}
     void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override {}
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override {}
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override {}
 
     int numDraws() const { return fNumDraws; }
 
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index c628ab5..577b814 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -161,20 +161,22 @@
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t, GrGpuBufferType, GrAccessPattern,
                                       const void*) override;
 
-    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height, GrColorType,
-                      void* buffer, size_t rowBytes) override;
+    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
+                      GrColorType surfaceColorType, GrColorType bufferColorType, void* buffer,
+                      size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface*, int left, int top, int width, int height, GrColorType,
+    bool onWritePixels(GrSurface*, int left, int top, int width, int height,
+                       GrColorType surfaceColorType, GrColorType bufferColorType,
                        const GrMipLevel[], int mipLevelCount) override;
 
-    bool onTransferPixelsTo(GrTexture*,
-                            int left, int top, int width, int height,
-                            GrColorType, GrGpuBuffer*,
+    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
+                            GrColorType textureColorType, GrColorType bufferColorType, GrGpuBuffer*,
                             size_t offset, size_t rowBytes) override {
         // TODO: not sure this is worth the work since nobody uses it
         return false;
     }
-    bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
+    bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
+                              GrColorType surfaceColorType, GrColorType bufferColorType,
                               GrGpuBuffer*, size_t offset) override {
         // TODO: Will need to implement this to support async read backs.
         return false;
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 7cd7a79..e9e847f 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -887,8 +887,8 @@
 }
 
 bool GrMtlGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                             GrColorType srcColorType, const GrMipLevel texels[],
-                             int mipLevelCount) {
+                             GrColorType surfaceColorType, GrColorType srcColorType,
+                             const GrMipLevel texels[], int mipLevelCount) {
     GrMtlTexture* mtlTexture = static_cast<GrMtlTexture*>(surface->asTexture());
     // TODO: In principle we should be able to support pure rendertargets as well, but
     // until we find a use case we'll only support texture rendertargets.
@@ -908,7 +908,8 @@
 }
 
 bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType dstColorType, void* buffer, size_t rowBytes) {
+                            GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                            size_t rowBytes) {
     SkASSERT(surface);
     if (!check_max_blit_width(width)) {
         return false;
diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.h b/src/gpu/mtl/GrMtlGpuCommandBuffer.h
index c3651ff..723ac07 100644
--- a/src/gpu/mtl/GrMtlGpuCommandBuffer.h
+++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.h
@@ -32,10 +32,12 @@
     void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override {
         fGpu->copySurface(fTexture, src, srcRect, dstPoint);
     }
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override {
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override {
         fGpu->transferPixelsFrom(fTexture, srcRect.fLeft, srcRect.fTop, srcRect.width(),
-                                 srcRect.height(), bufferColorType, transferBuffer, offset);
+                                 srcRect.height(), surfaceColorType, bufferColorType,
+                                 transferBuffer, offset);
     }
     void insertEventMarker(const char* msg) override {}
 
@@ -65,8 +67,9 @@
         // TODO: this could be more efficient
         state->doUpload(upload);
     }
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override;
+    void transferFrom(const SkIRect& srcRect, GrColorType textureColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override;
     void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
 
     void submit();
diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
index e03efec..a86d779 100644
--- a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
+++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
@@ -65,13 +65,15 @@
     fGpu->copySurface(fRenderTarget, src, srcRect, dstPoint);
 }
 
-void GrMtlGpuRTCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                                           GrGpuBuffer* transferBuffer, size_t offset) {
+void GrMtlGpuRTCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                                           GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                                           size_t offset) {
     // We cannot have an active encoder when we call transferFrom since it requires its own
     // command encoder.
     SkASSERT(nil == fActiveRenderCmdEncoder);
     fGpu->transferPixelsFrom(fRenderTarget, srcRect.fLeft, srcRect.fTop, srcRect.width(),
-                             srcRect.height(), bufferColorType, transferBuffer, offset);
+                             srcRect.height(), surfaceColorType, bufferColorType, transferBuffer,
+                             offset);
 }
 
 GrMtlPipelineState* GrMtlGpuRTCommandBuffer::prepareDrawState(
diff --git a/src/gpu/ops/GrTransferFromOp.cpp b/src/gpu/ops/GrTransferFromOp.cpp
index 5ae9509..be5490b 100644
--- a/src/gpu/ops/GrTransferFromOp.cpp
+++ b/src/gpu/ops/GrTransferFromOp.cpp
@@ -14,13 +14,16 @@
 
 std::unique_ptr<GrOp> GrTransferFromOp::Make(GrRecordingContext* context,
                                              const SkIRect& srcRect,
+                                             GrColorType surfaceColorType,
                                              GrColorType dstColorType,
                                              sk_sp<GrGpuBuffer> dstBuffer,
                                              size_t dstOffset) {
     GrOpMemoryPool* pool = context->priv().opMemoryPool();
-    return pool->allocate<GrTransferFromOp>(srcRect, dstColorType, std::move(dstBuffer), dstOffset);
+    return pool->allocate<GrTransferFromOp>(
+            srcRect, surfaceColorType, dstColorType, std::move(dstBuffer), dstOffset);
 }
 
 void GrTransferFromOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
-    state->commandBuffer()->transferFrom(fSrcRect, fDstColorType, fDstBuffer.get(), fDstOffset);
+    state->commandBuffer()->transferFrom(
+            fSrcRect, fSurfaceColorType, fDstColorType, fDstBuffer.get(), fDstOffset);
 }
diff --git a/src/gpu/ops/GrTransferFromOp.h b/src/gpu/ops/GrTransferFromOp.h
index abf824e..f611fc8 100644
--- a/src/gpu/ops/GrTransferFromOp.h
+++ b/src/gpu/ops/GrTransferFromOp.h
@@ -21,6 +21,7 @@
 
     static std::unique_ptr<GrOp> Make(GrRecordingContext*,
                                       const SkIRect& srcRect,
+                                      GrColorType surfaceColorType,
                                       GrColorType dstColorType,
                                       sk_sp<GrGpuBuffer> dstBuffer,
                                       size_t dstOffset);
@@ -32,10 +33,11 @@
         SkString string;
         string = INHERITED::dumpInfo();
         string.appendf(
-                "bufferID:: %d offset: %zu, color type: %d\n"
+                "bufferID:: %d offset: %zu, surf color type: %d, dst color type: %d\n"
                 "srcRect: [ L: %d, T: %d, R: %d, B: %d ]\n",
-                fDstBuffer->uniqueID().asUInt(), fDstOffset, (int)fDstColorType, fSrcRect.fLeft,
-                fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
+                fDstBuffer->uniqueID().asUInt(), fDstOffset, (int)fSurfaceColorType,
+                (int)fDstColorType, fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight,
+                fSrcRect.fBottom);
         return string;
     }
 #endif
@@ -44,6 +46,7 @@
     friend class GrOpMemoryPool;  // for ctor
 
     GrTransferFromOp(const SkIRect& srcRect,
+                     GrColorType surfaceColorType,
                      GrColorType dstColorType,
                      sk_sp<GrGpuBuffer> dstBuffer,
                      size_t dstOffset)
@@ -51,6 +54,7 @@
             , fDstBuffer(std::move(dstBuffer))
             , fDstOffset(dstOffset)
             , fSrcRect(srcRect)
+            , fSurfaceColorType(surfaceColorType)
             , fDstColorType(dstColorType) {
         this->setBounds(SkRect::Make(srcRect), HasAABloat::kNo, IsZeroArea::kNo);
     }
@@ -62,6 +66,7 @@
     sk_sp<GrGpuBuffer> fDstBuffer;
     size_t fDstOffset;
     SkIRect fSrcRect;
+    GrColorType fSurfaceColorType;
     GrColorType fDstColorType;
 
     typedef GrOp INHERITED;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 9f96d18..4291eb3 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -421,8 +421,8 @@
 }
 
 bool GrVkGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
-                            GrColorType srcColorType, const GrMipLevel texels[],
-                            int mipLevelCount) {
+                            GrColorType surfaceColorType, GrColorType srcColorType,
+                            const GrMipLevel texels[], int mipLevelCount) {
     GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture());
     if (!vkTex) {
         return false;
@@ -462,8 +462,9 @@
 }
 
 bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
-                                 GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
-                                 size_t bufferOffset, size_t rowBytes) {
+                                 GrColorType surfaceColorType, GrColorType bufferColorType,
+                                 GrGpuBuffer* transferBuffer, size_t bufferOffset,
+                                 size_t rowBytes) {
     // Vulkan only supports offsets that are both 4-byte aligned and aligned to a pixel.
     if ((bufferOffset & 0x3) || (bufferOffset % GrColorTypeBytesPerPixel(bufferColorType))) {
         return false;
@@ -518,8 +519,8 @@
 }
 
 bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                                   GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
-                                   size_t offset) {
+                                   GrColorType surfaceColorType, GrColorType bufferColorType,
+                                   GrGpuBuffer* transferBuffer, size_t offset) {
     SkASSERT(surface);
     SkASSERT(transferBuffer);
     if (fProtectedContext == GrProtected::kYes) {
@@ -2265,7 +2266,8 @@
 }
 
 bool GrVkGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
-                           GrColorType dstColorType, void* buffer, size_t rowBytes) {
+                           GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                           size_t rowBytes) {
     if (surface->isProtected()) {
         return false;
     }
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index fc63492..e91fa87 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -216,16 +216,20 @@
     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,
-                      void* buffer, size_t rowBytes) override;
+    bool onReadPixels(GrSurface* surface, int left, int top, int width, int height,
+                      GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
+                      size_t rowBytes) override;
 
-    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height, GrColorType,
+    bool onWritePixels(GrSurface* surface, int left, int top, int width, int height,
+                       GrColorType surfaceColorType, GrColorType srcColorType,
                        const GrMipLevel texels[], int mipLevelCount) override;
 
-    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height, GrColorType,
+    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
+                            GrColorType textureColorType, GrColorType bufferColorType,
                             GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) override;
     bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
-                              GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override;
+                              GrColorType surfaceColorType, GrColorType bufferColorType,
+                              GrGpuBuffer* transferBuffer, size_t offset) override;
 
     bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
                        const SkIPoint& dstPoint, bool canDiscardOutsideDstRect) override;
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index efac602..8fd5f59 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -66,23 +66,25 @@
 
 class TransferFrom : public GrVkPrimaryCommandBufferTask {
 public:
-    TransferFrom(const SkIRect& srcRect, GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
-                 size_t offset)
+    TransferFrom(const SkIRect& srcRect, GrColorType surfaceColorType, GrColorType bufferColorType,
+                 GrGpuBuffer* transferBuffer, size_t offset)
             : fTransferBuffer(sk_ref_sp(transferBuffer))
             , fOffset(offset)
             , fSrcRect(srcRect)
+            , fSurfaceColorType(surfaceColorType)
             , fBufferColorType(bufferColorType) {}
 
     void execute(const Args& args) override {
         args.fGpu->transferPixelsFrom(args.fSurface, fSrcRect.fLeft, fSrcRect.fTop,
-                                      fSrcRect.width(), fSrcRect.height(), fBufferColorType,
-                                      fTransferBuffer.get(), fOffset);
+                                      fSrcRect.width(), fSrcRect.height(), fSurfaceColorType,
+                                      fBufferColorType, fTransferBuffer.get(), fOffset);
     }
 
 private:
     sk_sp<GrGpuBuffer> fTransferBuffer;
     size_t fOffset;
     SkIRect fSrcRect;
+    GrColorType fSurfaceColorType;
     GrColorType fBufferColorType;
 };
 
@@ -96,9 +98,11 @@
     fTasks.emplace<Copy>(src, srcRect, dstPoint, false);
 }
 
-void GrVkGpuTextureCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
+void GrVkGpuTextureCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                                               GrColorType bufferColorType,
                                                GrGpuBuffer* transferBuffer, size_t offset) {
-    fTasks.emplace<TransferFrom>(srcRect, bufferColorType, transferBuffer, offset);
+    fTasks.emplace<TransferFrom>(srcRect, surfaceColorType, bufferColorType, transferBuffer,
+                                 offset);
 }
 
 void GrVkGpuTextureCommandBuffer::insertEventMarker(const char* msg) {
@@ -621,13 +625,15 @@
     }
 }
 
-void GrVkGpuRTCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                                          GrGpuBuffer* transferBuffer, size_t offset) {
+void GrVkGpuRTCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                                          GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                                          size_t offset) {
     CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
     if (!cbInfo.fIsEmpty) {
         this->addAdditionalRenderPass();
     }
-    fPreCommandBufferTasks.emplace<TransferFrom>(srcRect, bufferColorType, transferBuffer, offset);
+    fPreCommandBufferTasks.emplace<TransferFrom>(srcRect, surfaceColorType, bufferColorType,
+                                                 transferBuffer, offset);
     ++fCommandBufferInfos[fCurrentCmdInfo].fNumPreCmds;
 }
 
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.h b/src/gpu/vk/GrVkGpuCommandBuffer.h
index 587db76..0ca500e 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.h
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.h
@@ -46,8 +46,9 @@
     GrVkGpuTextureCommandBuffer(GrVkGpu* gpu) : fGpu(gpu) {}
 
     void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override;
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override;
 
     void insertEventMarker(const char*) override;
 
@@ -103,8 +104,9 @@
     void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override;
 
     void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
-    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
-                      GrGpuBuffer* transferBuffer, size_t offset) override;
+    void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
+                      GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
+                      size_t offset) override;
 
     void executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) override;
 
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index 3c12933..70c1b40 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -395,7 +395,8 @@
         // Try the low level write.
         context->flush();
         auto gpuWriteResult = context->priv().getGpu()->writePixels(
-                proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888, write.addr32(),
+                proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888,
+                GrColorType::kRGBA_8888, write.addr32(),
                 kSize * GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
         REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
 
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
index 45bf4ac..e55f4d4 100644
--- a/tests/TransferPixelsTest.cpp
+++ b/tests/TransferPixelsTest.cpp
@@ -63,7 +63,7 @@
     }
 }
 
-bool read_pixels_from_texture(GrTexture* texture, GrColorType dstColorType, char* dst,
+bool read_pixels_from_texture(GrTexture* texture, GrColorType colorType, char* dst,
                               float tolerances[4]) {
     auto* context = texture->getContext();
     auto* gpu = context->priv().getGpu();
@@ -71,27 +71,27 @@
 
     int w = texture->width();
     int h = texture->height();
-    size_t rowBytes = GrColorTypeBytesPerPixel(dstColorType) * w;
+    size_t rowBytes = GrColorTypeBytesPerPixel(colorType) * w;
 
     GrColorType srcCT = GrPixelConfigToColorType(texture->config());
 
-    GrCaps::SupportedRead supportedRead = caps->supportedReadPixelsColorType(
-            srcCT, texture->backendFormat(), dstColorType);
+    GrCaps::SupportedRead supportedRead =
+            caps->supportedReadPixelsColorType(srcCT, texture->backendFormat(), colorType);
     std::fill_n(tolerances, 4, 0);
-    if (supportedRead.fColorType != dstColorType) {
+    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,
-                             supportedRead.fColorType, tmpPixels.get(), tmpRowBytes)) {
+        if (!gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType,
+                             tmpPixels.get(), tmpRowBytes)) {
             return false;
         }
         GrPixelInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
-        GrPixelInfo dstInfo(dstColorType,             kUnpremul_SkAlphaType, nullptr, w, h);
+        GrPixelInfo dstInfo(colorType,                kUnpremul_SkAlphaType, nullptr, w, h);
         determine_tolerances(tmpInfo.colorType(), dstInfo.colorType(), tolerances);
         return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, tmpPixels.get(), tmpRowBytes,
                                false);
     }
-    return gpu->readPixels(texture, 0, 0, w, h, supportedRead.fColorType, dst, rowBytes);
+    return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes);
 }
 
 void basic_transfer_to_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType,
@@ -171,7 +171,7 @@
     // transfer full data
 
     bool result;
-    result = gpu->transferPixelsTo(tex.get(), 0, 0, kTextureWidth, kTextureHeight,
+    result = gpu->transferPixelsTo(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
                                    allowedSrc.fColorType, buffer.get(), 0, srcRowBytes);
     REPORTER_ASSERT(reporter, result);
 
@@ -229,10 +229,10 @@
     memcpy(data, srcData.get(), size);
     buffer->unmap();
 
-    result = gpu->transferPixelsTo(tex.get(), left, top, width, height, allowedSrc.fColorType,
-                                   buffer.get(), offset, srcRowBytes);
+    result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType,
+                                   allowedSrc.fColorType, buffer.get(), offset, srcRowBytes);
     if (!result) {
-        gpu->transferPixelsTo(tex.get(), left, top, width, height, allowedSrc.fColorType,
+        gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, allowedSrc.fColorType,
                               buffer.get(), offset, srcRowBytes);
         ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
                static_cast<int>(colorType));
@@ -334,7 +334,7 @@
 
     //////////////////////////
     // transfer full data
-    bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTextureWidth, kTextureHeight,
+    bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
                                           allowedRead.fColorType, buffer.get(), 0);
     if (!result) {
         ERRORF(reporter, "transferPixelsFrom failed.");
@@ -379,8 +379,8 @@
     ///////////////////////
     // Now test a partial read at an offset into the buffer.
     result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
-                                     kPartialHeight, allowedRead.fColorType, buffer.get(),
-                                     partialReadOffset);
+                                     kPartialHeight, colorType, allowedRead.fColorType,
+                                     buffer.get(), partialReadOffset);
     if (!result) {
         ERRORF(reporter, "transferPixelsFrom failed.");
         return;