GrConvertPixels takes pixmaps

Add GrCPixmap, a GrPixmap but with const void* instead of void*. Share
impl via template base class GrPixmapBase.

Change-Id: I7dfdf24a73c1bc8557ff7b90f93a9399da2f3f75
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350022
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/experimental/ddlbench/ddlbench.cpp b/experimental/ddlbench/ddlbench.cpp
index 9bb09d1..b4a6160 100644
--- a/experimental/ddlbench/ddlbench.cpp
+++ b/experimental/ddlbench/ddlbench.cpp
@@ -3,21 +3,17 @@
 
 #include "include/core/SkCanvas.h"
 #include "include/core/SkGraphics.h"
+#include "include/core/SkPicture.h"
 #include "include/core/SkScalar.h"
 #include "include/core/SkSurface.h"
 #include "include/gpu/GrDirectContext.h"
 #include "include/private/SkSLDefines.h"
-
 #include "src/core/SkOSFile.h"
-
+#include "src/gpu/GrCaps.h"
 #include "src/gpu/GrDirectContextPriv.h"
-
 #include "src/utils/SkOSPath.h"
-
 #include "tools/DDLPromiseImageHelper.h"
-#include "tools/DDLTileHelper.h"
 #include "tools/ToolUtils.h"
-
 #include "tools/flags/CommandLineFlags.h"
 #include "tools/gpu/GrContextFactory.h"
 #include "tools/gpu/TestContext.h"
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index 7af2cd6..6c47c95 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -18,6 +18,7 @@
 #include "src/core/SkUtils.h"
 #include "src/gpu/GrColor.h"
 #include "src/gpu/GrImageInfo.h"
+#include "src/gpu/GrPixmap.h"
 
 struct ETC1Block {
     uint32_t fHigh;
@@ -507,43 +508,36 @@
     pipeline->append_gamut_clamp_if_normalized(fakeII);
 }
 
-bool GrConvertPixels(const GrImageInfo& dstInfo,       void* dst, size_t dstRB,
-                     const GrImageInfo& srcInfo, const void* src, size_t srcRB,
-                     bool flipY) {
+bool GrConvertPixels(const GrPixmap& dst, const GrCPixmap& src, bool flipY) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-    if (srcInfo.colorType() == GrColorType::kRGB_888) {
+    if (src.colorType() == GrColorType::kRGB_888) {
         // We don't expect to have to convert from this format.
         return false;
     }
-    if (srcInfo.dimensions().isEmpty() || dstInfo.dimensions().isEmpty()) {
+    if (src.dimensions().isEmpty() || dst.dimensions().isEmpty()) {
         return false;
     }
-    if (srcInfo.colorType() == GrColorType::kUnknown ||
-        dstInfo.colorType() == GrColorType::kUnknown) {
+    if (src.colorType() == GrColorType::kUnknown || dst.colorType() == GrColorType::kUnknown) {
         return false;
     }
-    if (!src || !dst) {
+    if (!src.hasPixels() || !dst.hasPixels()) {
         return false;
     }
-    if (dstInfo.dimensions() != srcInfo.dimensions()) {
+    if (dst.dimensions() != src.dimensions()) {
         return false;
     }
-    if (dstRB < dstInfo.minRowBytes() || srcRB < srcInfo.minRowBytes()) {
-        return false;
-    }
-    if (dstInfo.colorType() == GrColorType::kRGB_888) {
+    if (dst.colorType() == GrColorType::kRGB_888) {
         // SkRasterPipeline doesn't handle writing to RGB_888. So we have it write to RGB_888x and
-        // then do another conversion that does the 24bit packing.
-        auto tempDstInfo = dstInfo.makeColorType(GrColorType::kRGB_888x);
-        auto tempRB = tempDstInfo.minRowBytes();
-        std::unique_ptr<char[]> tempDst(new char[tempRB * tempDstInfo.height()]);
-        if (!GrConvertPixels(tempDstInfo, tempDst.get(), tempRB, srcInfo, src, srcRB, flipY)) {
+        // then do another conversion that does the 24bit packing. We could be cleverer and skip the
+        // temp pixmap if this is the only conversion but this is rare so keeping it simple.
+        GrPixmap temp = GrPixmap::Allocate(dst.info().makeColorType(GrColorType::kRGB_888x));
+        if (!GrConvertPixels(temp, src, flipY)) {
             return false;
         }
-        auto* tRow = reinterpret_cast<const char*>(tempDst.get());
-        auto* dRow = reinterpret_cast<char*>(dst);
-        for (int y = 0; y < dstInfo.height(); ++y, tRow += tempRB, dRow += dstRB) {
-            for (int x = 0; x < dstInfo.width(); ++x) {
+        auto* tRow = reinterpret_cast<const char*>(temp.addr());
+        auto* dRow = reinterpret_cast<char*>(dst.addr());
+        for (int y = 0; y < dst.height(); ++y, tRow += temp.rowBytes(), dRow += dst.rowBytes()) {
+            for (int x = 0; x < dst.width(); ++x) {
                 auto t = reinterpret_cast<const uint32_t*>(tRow + x * sizeof(uint32_t));
                 auto d = reinterpret_cast<uint32_t*>(dRow + x * 3);
                 memcpy(d, t, 3);
@@ -552,31 +546,32 @@
         return true;
     }
 
-    size_t srcBpp = srcInfo.bpp();
-    size_t dstBpp = dstInfo.bpp();
+    size_t srcBpp = src.info().bpp();
+    size_t dstBpp = dst.info().bpp();
 
     // SkRasterPipeline operates on row-pixels not row-bytes.
-    SkASSERT(dstRB % dstBpp == 0);
-    SkASSERT(srcRB % srcBpp == 0);
+    SkASSERT(dst.rowBytes() % dstBpp == 0);
+    SkASSERT(src.rowBytes() % srcBpp == 0);
 
-    bool premul   = srcInfo.alphaType() == kUnpremul_SkAlphaType &&
-                    dstInfo.alphaType() == kPremul_SkAlphaType;
-    bool unpremul = srcInfo.alphaType() == kPremul_SkAlphaType &&
-                    dstInfo.alphaType() == kUnpremul_SkAlphaType;
+    bool premul   = src.alphaType() == kUnpremul_SkAlphaType &&
+                    dst.alphaType() == kPremul_SkAlphaType;
+    bool unpremul = src.alphaType() == kPremul_SkAlphaType &&
+                    dst.alphaType() == kUnpremul_SkAlphaType;
     bool alphaOrCSConversion =
-            premul || unpremul || !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
+            premul || unpremul || !SkColorSpace::Equals(src.colorSpace(), dst.colorSpace());
 
-    if (srcInfo.colorType() == dstInfo.colorType() && !alphaOrCSConversion) {
-        size_t tightRB = dstBpp * dstInfo.width();
+    if (src.colorType() == dst.colorType() && !alphaOrCSConversion) {
+        size_t tightRB = dstBpp * dst.width();
         if (flipY) {
-            dst = static_cast<char*>(dst) + dstRB * (dstInfo.height() - 1);
-            for (int y = 0; y < dstInfo.height(); ++y) {
-                memcpy(dst, src, tightRB);
-                src = static_cast<const char*>(src) + srcRB;
-                dst = static_cast<      char*>(dst) - dstRB;
+            auto s = static_cast<const char*>(src.addr());
+            auto d = SkTAddOffset<char>(dst.addr(), dst.rowBytes()*(dst.height() - 1));
+            for (int y = 0; y < dst.height(); ++y, d -= dst.rowBytes(), s += src.rowBytes()) {
+                memcpy(d, s, tightRB);
             }
         } else {
-            SkRectMemcpy(dst, dstRB, src, srcRB, tightRB, srcInfo.height());
+            SkRectMemcpy(dst.addr(), dst.rowBytes(),
+                         src.addr(), src.rowBytes(),
+                         tightRB, src.height());
         }
         return true;
     }
@@ -584,34 +579,38 @@
     SkRasterPipeline::StockStage load;
     bool srcIsNormalized;
     bool srcIsSRGB;
-    auto loadSwizzle =
-            get_load_and_src_swizzle(srcInfo.colorType(), &load, &srcIsNormalized, &srcIsSRGB);
+    auto loadSwizzle = get_load_and_src_swizzle(src.colorType(),
+                                                &load,
+                                                &srcIsNormalized,
+                                                &srcIsSRGB);
 
     SkRasterPipeline::StockStage store;
     LumMode lumMode;
     bool dstIsNormalized;
     bool dstIsSRGB;
-    auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &lumMode,
-                                                  &dstIsNormalized, &dstIsSRGB);
+    auto storeSwizzle = get_dst_swizzle_and_store(dst.colorType(),
+                                                  &store,
+                                                  &lumMode,
+                                                  &dstIsNormalized,
+                                                  &dstIsSRGB);
 
     bool clampGamut;
     SkTLazy<SkColorSpaceXformSteps> steps;
     GrSwizzle loadStoreSwizzle;
     if (alphaOrCSConversion) {
-        steps.init(srcInfo.colorSpace(), srcInfo.alphaType(),
-                   dstInfo.colorSpace(), dstInfo.alphaType());
-        clampGamut = dstIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
+        steps.init(src.colorSpace(), src.alphaType(), dst.colorSpace(), dst.alphaType());
+        clampGamut = dstIsNormalized && dst.alphaType() == kPremul_SkAlphaType;
     } else {
-        clampGamut =
-                dstIsNormalized && !srcIsNormalized && dstInfo.alphaType() == kPremul_SkAlphaType;
+        clampGamut = dstIsNormalized && !srcIsNormalized && dst.alphaType() == kPremul_SkAlphaType;
         if (!clampGamut) {
             loadStoreSwizzle = GrSwizzle::Concat(loadSwizzle, storeSwizzle);
         }
     }
     int cnt = 1;
-    int height = srcInfo.height();
-    SkRasterPipeline_MemoryCtx srcCtx{const_cast<void*>(src), SkToInt(srcRB / srcBpp)},
-                               dstCtx{                  dst , SkToInt(dstRB / dstBpp)};
+    int height = src.height();
+    SkRasterPipeline_MemoryCtx
+            srcCtx{const_cast<void*>(src.addr()), SkToInt(src.rowBytes()/srcBpp)},
+            dstCtx{                   dst.addr(), SkToInt(dst.rowBytes()/dstBpp)};
 
     if (flipY) {
         // It *almost* works to point the src at the last row and negate the stride and run the
@@ -619,7 +618,7 @@
         // variables so it winds up relying on unsigned overflow math. It works out in practice
         // but UBSAN says "no!" as it's technically undefined and in theory a compiler could emit
         // code that didn't do what is intended. So we go one row at a time. :(
-        srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + srcRB * (height - 1);
+        srcCtx.pixels = static_cast<char*>(srcCtx.pixels) + src.rowBytes()*(height - 1);
         std::swap(cnt, height);
     }
 
@@ -669,9 +668,9 @@
             loadStoreSwizzle.apply(&pipeline);
         }
         pipeline.append(store, &dstCtx);
-        pipeline.run(0, 0, srcInfo.width(), height);
-        srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - srcRB;
-        dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dstRB;
+        pipeline.run(0, 0, src.width(), height);
+        srcCtx.pixels = static_cast<char*>(srcCtx.pixels) - src.rowBytes();
+        dstCtx.pixels = static_cast<char*>(dstCtx.pixels) + dst.rowBytes();
     }
     return true;
 }
diff --git a/src/gpu/GrDataUtils.h b/src/gpu/GrDataUtils.h
index 54fb478..dbc9661 100644
--- a/src/gpu/GrDataUtils.h
+++ b/src/gpu/GrDataUtils.h
@@ -10,8 +10,12 @@
 
 #include "include/core/SkColor.h"
 #include "include/private/GrTypesPriv.h"
-#include "src/gpu/GrPixmap.h"
-#include "src/gpu/GrSwizzle.h"
+#include "include/private/SkTArray.h"
+
+class GrImageInfo;
+class GrCPixmap;
+class GrPixmap;
+class SkPixmap;
 
 size_t GrNumBlocks(SkImage::CompressionType, SkISize baseDimensions);
 
@@ -32,17 +36,7 @@
 void GrFillInCompressedData(SkImage::CompressionType, SkISize dimensions, GrMipmapped, char* dest,
                             const SkColor4f& color);
 
-// Swizzle param is applied after loading and before converting from srcInfo to dstInfo.
-bool GrConvertPixels(const GrImageInfo& dstInfo,       void* dst, size_t dstRB,
-                     const GrImageInfo& srcInfo, const void* src, size_t srcRB,
-                     bool flipY = false);
-
-// Convenience version for src/dst pixmaps.
-inline bool GrConvertPixels(const GrPixmap& dst, const GrPixmap& src, bool flipY = false) {
-    return GrConvertPixels(dst.info(), dst.addr(), dst.rowBytes(),
-                           src.info(), src.addr(), src.rowBytes(),
-                           flipY);
-}
+bool GrConvertPixels(const GrPixmap& dst, const GrCPixmap& src, bool flipY = false);
 
 /** Clears the dst image to a constant color. */
 bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, SkColor4f color);
diff --git a/src/gpu/GrImageInfo.h b/src/gpu/GrImageInfo.h
index fefea1b..93dd314 100644
--- a/src/gpu/GrImageInfo.h
+++ b/src/gpu/GrImageInfo.h
@@ -44,6 +44,10 @@
         return {this->colorType(), at, this->refColorSpace(), this->width(), this->height()};
     }
 
+    GrImageInfo makeColorSpace(sk_sp<SkColorSpace> cs) const {
+        return {this->colorType(), this->alphaType(), std::move(cs), this->width(), this->height()};
+    }
+
     GrImageInfo makeDimensions(SkISize dimensions) const {
         return {this->colorType(), this->alphaType(), this->refColorSpace(), dimensions};
     }
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index b79950a..36f01be 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -114,12 +114,12 @@
         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;
-            GrImageInfo srcInfo(colorType, kAT, nullptr, width, height);
-            GrImageInfo tmpInfo(supportedWrite.fColorType, kAT, nullptr, width,
-                                height);
-            if (!GrConvertPixels(tmpInfo, tmpPixels.get(), tightRB, srcInfo, buffer, rowBytes)) {
+            // 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);
+            if (!GrConvertPixels( GrPixmap(tmpInfo, tmpPixels.get(), tightRB ),
+                                 GrCPixmap(srcInfo,          buffer, rowBytes))) {
                 return false;
             }
             rowBytes = tightRB;
diff --git a/src/gpu/GrPixmap.h b/src/gpu/GrPixmap.h
index 383bcb4..3aa3f49 100644
--- a/src/gpu/GrPixmap.h
+++ b/src/gpu/GrPixmap.h
@@ -12,39 +12,12 @@
 #include "include/core/SkPixmap.h"
 #include "src/gpu/GrImageInfo.h"
 
-class GrPixmap {
+template <typename T, typename DERIVED> class GrPixmapBase {
 public:
-    GrPixmap() = default;
-    GrPixmap(const GrPixmap&) = default;
-    GrPixmap(GrPixmap&&) = default;
-    GrPixmap& operator=(const GrPixmap&) = default;
-    GrPixmap& operator=(GrPixmap&&) = default;
-
-    GrPixmap(GrImageInfo info, void* addr, size_t rowBytes)
-            : fAddr(addr), fRowBytes(rowBytes), fInfo(std::move(info)) {
-        if (fRowBytes < info.minRowBytes() || !addr) {
-            *this = {};
-        }
-    }
-    /* implicit */ GrPixmap(const SkPixmap& pixmap)
-            : GrPixmap(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes()) {}
-
-    /**
-     * Returns a GrPixmap that owns its backing store. Copies of the pixmap will share ownership.
-     */
-    static GrPixmap Allocate(const GrImageInfo& info) {
-        size_t rb = info.minRowBytes();
-        size_t size = info.height()*rb;
-        if (!size) {
-            return {};
-        }
-        return GrPixmap(info, SkData::MakeUninitialized(size), rb);
-    }
-
     const GrImageInfo& info() const { return fInfo; }
     const GrColorInfo& colorInfo() const { return fInfo.colorInfo(); }
 
-    void* addr() const { return fAddr; }
+    T* addr() const { return fAddr; }
     size_t rowBytes() const { return fRowBytes; }
 
     bool hasPixels() const { return SkToBool(fAddr); }
@@ -56,6 +29,7 @@
     SkISize dimensions() const { return fInfo.dimensions(); }
     GrColorType colorType() const { return fInfo.colorType(); }
     SkAlphaType alphaType() const { return fInfo.alphaType(); }
+    SkColorSpace* colorSpace() const { return fInfo.colorSpace(); }
 
     /**
      * Map this pixmap to a rect in a surface of indicated dimensions at offset surfacePt. Clip the
@@ -64,29 +38,107 @@
      * to the upper left of the clipped rectangle. The returned pixmap will refer to the portion
      * of the original pixmap inside the surface bounds.
      */
-    GrPixmap clip(SkISize surfaceDims, SkIPoint* surfacePt) {
+    DERIVED clip(SkISize surfaceDims, SkIPoint* surfacePt) {
         auto bounds = SkIRect::MakeSize(surfaceDims);
         auto rect = SkIRect::MakePtSize(*surfacePt, this->dimensions());
         if (!rect.intersect(bounds)) {
             return {};
         }
-        void* addr = static_cast<char*>(fAddr) + (rect.fTop  - surfacePt->fY)*fRowBytes +
-                                                 (rect.fLeft - surfacePt->fX)*fInfo.bpp();
+        T* addr = static_cast<sknonstd::copy_const_t<char, T>*>(fAddr) +
+                  (rect.fTop - surfacePt->fY) * fRowBytes +
+                  (rect.fLeft - surfacePt->fX) * fInfo.bpp();
         surfacePt->fX = rect.fLeft;
         surfacePt->fY = rect.fTop;
-        return {this->info().makeDimensions(rect.size()), addr, fRowBytes};
+        return DERIVED{this->info().makeDimensions(rect.size()), addr, fRowBytes};
+    }
+
+protected:
+    GrPixmapBase() = default;
+    GrPixmapBase(const GrPixmapBase& that) = default;
+    GrPixmapBase(GrPixmapBase&& that) = default;
+    GrPixmapBase& operator=(const GrPixmapBase& that) = default;
+    GrPixmapBase& operator=(GrPixmapBase&& that) = default;
+
+    GrPixmapBase(GrImageInfo info, T* addr, size_t rowBytes)
+            : fAddr(addr), fRowBytes(rowBytes), fInfo(std::move(info)) {
+        if (fRowBytes < info.minRowBytes() || !addr) {
+            *this = {};
+        }
+    }
+
+    GrPixmapBase(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
+            : GrPixmapBase(std::move(info), const_cast<void*>(storage->data()), rowBytes) {
+        fPixelStorage = std::move(storage);
+    }
+
+private:
+    T* fAddr = nullptr;
+    size_t fRowBytes = 0;
+    GrImageInfo fInfo;
+    sk_sp<SkData> fPixelStorage;
+};
+
+/** A pixmap with mutable pixels. */
+class GrPixmap : public GrPixmapBase<void, GrPixmap> {
+public:
+    GrPixmap() = default;
+    GrPixmap(const GrPixmap&) = default;
+    GrPixmap(GrPixmap&&) = default;
+    GrPixmap& operator=(const GrPixmap&) = default;
+    GrPixmap& operator=(GrPixmap&&) = default;
+
+    GrPixmap(GrImageInfo info, void* addr, size_t rowBytes) : GrPixmapBase(info, addr, rowBytes) {}
+
+    /* implicit */ GrPixmap(const SkPixmap& pixmap)
+            : GrPixmapBase(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes()) {}
+
+    /**
+     * Returns a GrPixmap that owns its backing store. Copies of the pixmap (as GrPixmap or
+     * GrCPixmap) will share ownership.
+     */
+    static GrPixmap Allocate(const GrImageInfo& info) {
+        size_t rb = info.minRowBytes();
+        size_t size = info.height()*rb;
+        if (!size) {
+            return {};
+        }
+        return GrPixmap(info, SkData::MakeUninitialized(size), rb);
     }
 
 private:
     GrPixmap(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
-            : GrPixmap(std::move(info), storage->writable_data(), rowBytes) {
-        fPixelStorage = std::move(storage);
+            : GrPixmapBase(std::move(info), std::move(storage), rowBytes) {}
+};
+
+/**
+ * A pixmap with immutable pixels. Note that this pixmap need not be the unique owner of the pixels
+ * and thus it is context-dependent whether the pixels could be manipulated externally.
+ */
+class GrCPixmap : public GrPixmapBase<const void, GrCPixmap> {
+public:
+    GrCPixmap() = default;
+    GrCPixmap(const GrCPixmap&) = default;
+    GrCPixmap(GrCPixmap&&) = default;
+    GrCPixmap& operator=(const GrCPixmap&) = default;
+    GrCPixmap& operator=(GrCPixmap&&) = default;
+
+    /* implicit*/ GrCPixmap(const GrPixmap& pixmap) {
+        if (pixmap.pixelStorage()) {
+            *this = GrCPixmap(pixmap.info(), pixmap.pixelStorage(), pixmap.rowBytes());
+        } else {
+            *this = GrCPixmap(pixmap.info(), pixmap.addr(), pixmap.rowBytes());
+        }
     }
 
-    void* fAddr = nullptr;
-    size_t fRowBytes = 0;
-    GrImageInfo fInfo;
-    sk_sp<SkData> fPixelStorage;
+    /* implicit */ GrCPixmap(const SkPixmap& pixmap)
+            : GrPixmapBase(pixmap.info(), pixmap.addr(), pixmap.rowBytes()) {}
+
+    GrCPixmap(GrImageInfo info, const void* addr, size_t rowBytes)
+            : GrPixmapBase(info, addr, rowBytes) {}
+
+private:
+    GrCPixmap(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
+            : GrPixmapBase(info, std::move(storage), rowBytes) {}
 };
 
 #endif
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index cc6e2c4..fc9e513 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -620,9 +620,10 @@
     data->reset(new char[tempRB * dimensions.fHeight]);
     outLevel->fPixels = data->get();
     outLevel->fRowBytes = tempRB;
-    GrImageInfo srcInfo(origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
+    GrImageInfo srcInfo(   origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
     GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
-    return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
+    return GrConvertPixels( GrPixmap(dstInfo,     data->get(),   tempRB),
+                           GrCPixmap(srcInfo, inLevel.fPixels, actualRB));
 }
 
 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 7c84826..2dfac24 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -354,7 +354,7 @@
     return true;
 }
 
-bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrPixmap src, SkIPoint pt) {
+bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrCPixmap src, SkIPoint pt) {
     ASSERT_SINGLE_OWNER
     RETURN_FALSE_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
@@ -1323,9 +1323,8 @@
                 void* dst, const void* src) {
             GrImageInfo srcInfo(supportedRead.fColorType, at, nullptr, w, h);
             GrImageInfo dstInfo(dstCT,                    at, nullptr, w, h);
-              GrConvertPixels(dstInfo, dst, dstInfo.minRowBytes(),
-                              srcInfo, src, srcInfo.minRowBytes(),
-                              /* flipY = */ false);
+            GrConvertPixels( GrPixmap(dstInfo, dst, dstInfo.minRowBytes()),
+                            GrCPixmap(srcInfo, src, srcInfo.minRowBytes()));
         };
     }
     return result;
diff --git a/src/gpu/GrSurfaceContext.h b/src/gpu/GrSurfaceContext.h
index b51d1af..664e89d 100644
--- a/src/gpu/GrSurfaceContext.h
+++ b/src/gpu/GrSurfaceContext.h
@@ -134,7 +134,7 @@
      * @param src           source for the write
      * @param dstPt         offset w/in the surface context at which to write
      */
-    bool writePixels(GrDirectContext* dContext, GrPixmap src, SkIPoint dstPt);
+    bool writePixels(GrDirectContext* dContext, GrCPixmap src, SkIPoint dstPt);
 
     GrSurfaceProxy* asSurfaceProxy() { return fReadView.proxy(); }
     const GrSurfaceProxy* asSurfaceProxy() const { return fReadView.proxy(); }
diff --git a/src/gpu/gl/GrGLContext.cpp b/src/gpu/gl/GrGLContext.cpp
index 74efd7f..c817207 100644
--- a/src/gpu/gl/GrGLContext.cpp
+++ b/src/gpu/gl/GrGLContext.cpp
@@ -6,6 +6,8 @@
  */
 
 #include "src/gpu/gl/GrGLContext.h"
+
+#include "include/gpu/GrContextOptions.h"
 #include "src/gpu/gl/GrGLGLSL.h"
 
 #ifdef SK_BUILD_FOR_ANDROID
diff --git a/tests/BackendAllocationTest.cpp b/tests/BackendAllocationTest.cpp
index 5510440..c2b60fb 100644
--- a/tests/BackendAllocationTest.cpp
+++ b/tests/BackendAllocationTest.cpp
@@ -227,7 +227,8 @@
     // Read back to SkColor4f.
     SkColor4f result;
     GrImageInfo resultII(GrColorType::kRGBA_F32, kUnpremul_SkAlphaType, nullptr, {1, 1});
-    GrConvertPixels(resultII, &result.fR, sizeof(result), ii, data.get(), ii.minRowBytes());
+    GrConvertPixels(GrPixmap(resultII,  &result.fR,   sizeof(result)),
+                    GrPixmap(      ii,  data.get(), ii.minRowBytes()));
     return result;
 }
 
diff --git a/tests/CopySurfaceTest.cpp b/tests/CopySurfaceTest.cpp
index 3a2f0d7..5127aa0 100644
--- a/tests/CopySurfaceTest.cpp
+++ b/tests/CopySurfaceTest.cpp
@@ -78,8 +78,8 @@
                     for (const SkIRect& srcRect : kSrcRects) {
                         for (const SkIPoint& dstPoint : kDstPoints) {
                             for (const SkImageInfo& ii: kImageInfos) {
-                                GrPixmap srcPM(ii, srcPixels.get(), kRowBytes);
-                                GrPixmap dstPM(ii, dstPixels.get(), kRowBytes);
+                                GrCPixmap srcPM(ii, srcPixels.get(), kRowBytes);
+                                GrPixmap  dstPM(ii, dstPixels.get(), kRowBytes);
                                 auto srcView = sk_gpu_test::MakeTextureProxyViewFromData(
                                         dContext, sRenderable, sOrigin, srcPM);
                                 auto dstView = sk_gpu_test::MakeTextureProxyViewFromData(
diff --git a/tests/FloatingPointTextureTest.cpp b/tests/FloatingPointTextureTest.cpp
index f575bbc..c210b5b 100644
--- a/tests/FloatingPointTextureTest.cpp
+++ b/tests/FloatingPointTextureTest.cpp
@@ -50,7 +50,7 @@
 
     for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
         GrImageInfo info(colorType, kPremul_SkAlphaType, nullptr, {DEV_W, DEV_H});
-        GrPixmap controlPixmap(info, controlPixelData.begin(), info.minRowBytes());
+        GrCPixmap controlPixmap(info, controlPixelData.begin(), info.minRowBytes());
         auto fpView = sk_gpu_test::MakeTextureProxyViewFromData(dContext,
                                                                 GrRenderable::kYes,
                                                                 origin,
diff --git a/tests/GradientTest.cpp b/tests/GradientTest.cpp
index e43e0a7..cf1bcfc 100644
--- a/tests/GradientTest.cpp
+++ b/tests/GradientTest.cpp
@@ -14,6 +14,7 @@
 #include "include/private/SkTemplates.h"
 #include "src/core/SkMatrixProvider.h"
 #include "src/core/SkTLazy.h"
+#include "src/gpu/GrColorInfo.h"
 #include "src/shaders/SkColorShader.h"
 #include "tests/Test.h"
 
diff --git a/tests/MultiPictureDocumentTest.cpp b/tests/MultiPictureDocumentTest.cpp
index 27dc745..bd8e2fa 100644
--- a/tests/MultiPictureDocumentTest.cpp
+++ b/tests/MultiPictureDocumentTest.cpp
@@ -9,6 +9,7 @@
  */
 
 #include "include/core/SkCanvas.h"
+#include "include/core/SkColorPriv.h"
 #include "include/core/SkColorSpace.h"
 #include "include/core/SkDocument.h"
 #include "include/core/SkFont.h"
@@ -18,6 +19,7 @@
 #include "include/core/SkString.h"
 #include "include/core/SkSurface.h"
 #include "include/core/SkTextBlob.h"
+#include "src/gpu/GrCaps.h"
 #include "src/utils/SkMultiPictureDocument.h"
 #include "tests/Test.h"
 #include "tools/SkSharingProc.h"
diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp
index aa16620..64894a9 100644
--- a/tests/ReadPixelsTest.cpp
+++ b/tests/ReadPixelsTest.cpp
@@ -6,8 +6,11 @@
  */
 
 #include "include/core/SkCanvas.h"
+#include "include/core/SkColorPriv.h"
 #include "include/core/SkImage.h"
 #include "include/core/SkSurface.h"
+#include "include/private/SkColorData.h"
+#include "include/private/SkHalf.h"
 #include "include/private/SkImageInfoPriv.h"
 #include "include/utils/SkNWayCanvas.h"
 #include "src/core/SkMathPriv.h"
diff --git a/tests/RectangleTextureTest.cpp b/tests/RectangleTextureTest.cpp
index 8133147..05def87 100644
--- a/tests/RectangleTextureTest.cpp
+++ b/tests/RectangleTextureTest.cpp
@@ -102,7 +102,7 @@
                          kPremul_SkAlphaType,
                          nullptr,
                          dstContext->dimensions());
-        GrPixmap pixmap(info, pixels.get(), dstContext->width()*sizeof(uint32_t));
+        GrCPixmap pixmap(info, pixels.get(), dstContext->width()*sizeof(uint32_t));
         auto srcView = sk_gpu_test::MakeTextureProxyViewFromData(dContext,
                                                                  renderable,
                                                                  origin,
diff --git a/tests/SRGBReadWritePixelsTest.cpp b/tests/SRGBReadWritePixelsTest.cpp
index 41ce18b..7f7d202 100644
--- a/tests/SRGBReadWritePixelsTest.cpp
+++ b/tests/SRGBReadWritePixelsTest.cpp
@@ -211,7 +211,7 @@
     auto writeII = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
                                      encoding_as_color_space(writeEncoding));
     auto data = make_data();
-    GrPixmap dataPM(writeII, data.get(), kW*sizeof(uint32_t));
+    GrCPixmap dataPM(writeII, data.get(), kW*sizeof(uint32_t));
     if (!surfaceContext->writePixels(dContext, dataPM, {0, 0})) {
         ERRORF(reporter, "Could not write %s to %s surface context.",
                encoding_as_str(writeEncoding), encoding_as_str(contextEncoding));
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index 85fbdd3..b295e93 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -13,6 +13,7 @@
 #include "include/core/SkSurface.h"
 #include "include/effects/SkRuntimeEffect.h"
 #include "include/gpu/GrDirectContext.h"
+#include "src/core/SkColorSpacePriv.h"
 #include "src/core/SkTLazy.h"
 #include "src/gpu/GrColor.h"
 #include "tests/Test.h"
diff --git a/tests/TestUtils.cpp b/tests/TestUtils.cpp
index 5fe1fcc..118034f 100644
--- a/tests/TestUtils.cpp
+++ b/tests/TestUtils.cpp
@@ -135,38 +135,30 @@
     return true;
 }
 
-using AccessPixelFn = const float*(const char* floatBuffer, int x, int y);
-
-bool compare_pixels(int width, int height,
-                    const char* floatA, std::function<AccessPixelFn>& atA,
-                    const char* floatB, std::function<AccessPixelFn>& atB,
-                    const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
-
-    for (int y = 0; y < height; ++y) {
-        for (int x = 0; x < width; ++x) {
-            const float* rgbaA = atA(floatA, x, y);
-            const float* rgbaB = atB(floatB, x, y);
-            float diffs[4];
-            bool bad = false;
-            for (int i = 0; i < 4; ++i) {
-                diffs[i] = rgbaB[i] - rgbaA[i];
-                if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
-                    bad = true;
-                }
-            }
-            if (bad) {
-                error(x, y, diffs);
-                return false;
-            }
+static bool compare_colors(int x, int y,
+                           const float rgbaA[],
+                           const float rgbaB[],
+                           const float tolRGBA[4],
+                           std::function<ComparePixmapsErrorReporter>& error) {
+    float diffs[4];
+    bool bad = false;
+    for (int i = 0; i < 4; ++i) {
+        diffs[i] = rgbaB[i] - rgbaA[i];
+        if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
+            bad = true;
         }
     }
+    if (bad) {
+        error(x, y, diffs);
+        return false;
+    }
     return true;
 }
 
 bool ComparePixels(const GrImageInfo& infoA, const char* a, size_t rowBytesA,
                    const GrImageInfo& infoB, const char* b, size_t rowBytesB,
                    const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
-    if (infoA.width() != infoB.width() || infoA.height() != infoB.height()) {
+    if (infoA.dimensions() != infoB.dimensions()) {
         static constexpr float kDummyDiffs[4] = {};
         error(-1, -1, kDummyDiffs);
         return false;
@@ -186,24 +178,31 @@
     } else {
         floatCS = SkColorSpace::MakeSRGBLinear();
     }
-    GrImageInfo floatInfo(GrColorType::kRGBA_F32, floatAlphaType, std::move(floatCS),
-                          infoA.width(), infoA.height());
+    GrImageInfo floatInfo(GrColorType::kRGBA_F32,
+                          floatAlphaType,
+                          std::move(floatCS),
+                          infoA.dimensions());
 
-    size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
-    size_t floatRowBytes = floatBpp * infoA.width();
-    std::unique_ptr<char[]> floatA(new char[floatRowBytes * infoA.height()]);
-    std::unique_ptr<char[]> floatB(new char[floatRowBytes * infoA.height()]);
-    SkAssertResult(GrConvertPixels(floatInfo, floatA.get(), floatRowBytes, infoA, a, rowBytesA));
-    SkAssertResult(GrConvertPixels(floatInfo, floatB.get(), floatRowBytes, infoB, b, rowBytesB));
+    GrPixmap floatA = GrPixmap::Allocate(floatInfo);
+    GrPixmap floatB = GrPixmap::Allocate(floatInfo);
+    SkAssertResult(GrConvertPixels(floatA, GrCPixmap(infoA, a, rowBytesA)));
+    SkAssertResult(GrConvertPixels(floatB, GrCPixmap(infoB, b, rowBytesB)));
 
-    auto at = std::function<AccessPixelFn>(
-        [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
-            return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
-        });
+    SkASSERT(floatA.rowBytes() == floatB.rowBytes());
+    auto at = [rb = floatA.rowBytes()](const void* base, int x, int y) {
+        return SkTAddOffset<const float>(base, y*rb + x*sizeof(float)*4);
+    };
 
-    return compare_pixels(infoA.width(), infoA.height(),
-                          floatA.get(), at, floatB.get(), at,
-                          tolRGBA, error);
+    for (int y = 0; y < floatA.height(); ++y) {
+        for (int x = 0; x < floatA.width(); ++x) {
+            const float* rgbaA = at(floatA.addr(), x, y);
+            const float* rgbaB = at(floatB.addr(), x, y);
+            if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
 bool ComparePixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
@@ -213,45 +212,44 @@
                          tolRGBA, error);
 }
 
-bool CheckSolidPixels(const SkColor4f& col, const SkPixmap& pixmap,
-                      const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
-
+bool CheckSolidPixels(const SkColor4f& col,
+                      const SkPixmap& pixmap,
+                      const float tolRGBA[4],
+                      std::function<ComparePixmapsErrorReporter>& error) {
     size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
 
-    std::unique_ptr<char[]> floatA(new char[floatBpp]);
     // First convert 'col' to be compatible with 'pixmap'
+    GrPixmap colorPixmap;
     {
         sk_sp<SkColorSpace> srcCS = SkColorSpace::MakeSRGBLinear();
-        GrImageInfo srcInfo(GrColorType::kRGBA_F32, kUnpremul_SkAlphaType, std::move(srcCS), 1, 1);
-        GrImageInfo dstInfo(GrColorType::kRGBA_F32, pixmap.alphaType(), pixmap.refColorSpace(), 1, 1);
-
-        SkAssertResult(GrConvertPixels(dstInfo, floatA.get(), floatBpp, srcInfo,
-                                       col.vec(), floatBpp));
+        GrImageInfo srcInfo(GrColorType::kRGBA_F32,
+                            kUnpremul_SkAlphaType,
+                            std::move(srcCS),
+                            {1, 1});
+        GrCPixmap srcPixmap(srcInfo, col.vec(), floatBpp);
+        GrImageInfo dstInfo =
+                srcInfo.makeAlphaType(pixmap.alphaType()).makeColorSpace(pixmap.refColorSpace());
+        colorPixmap = GrPixmap::Allocate(dstInfo);
+        SkAssertResult(GrConvertPixels(colorPixmap, srcPixmap));
     }
 
     size_t floatRowBytes = floatBpp * pixmap.width();
     std::unique_ptr<char[]> floatB(new char[floatRowBytes * pixmap.height()]);
     // Then convert 'pixmap' to RGBA_F32
-    {
-        GrImageInfo dstInfo(GrColorType::kRGBA_F32, pixmap.alphaType(), pixmap.refColorSpace(),
-                            pixmap.width(), pixmap.height());
+    GrPixmap f32Pixmap = GrPixmap::Allocate(pixmap.info().makeColorType(kRGBA_F32_SkColorType));
+    SkAssertResult(GrConvertPixels(f32Pixmap, pixmap));
 
-        SkAssertResult(GrConvertPixels(dstInfo, floatB.get(), floatRowBytes, pixmap.info(),
-                                       pixmap.addr(), pixmap.rowBytes()));
+    for (int y = 0; y < f32Pixmap.height(); ++y) {
+        for (int x = 0; x < f32Pixmap.width(); ++x) {
+            auto rgbaA = SkTAddOffset<const float>(f32Pixmap.addr(),
+                                                   f32Pixmap.rowBytes()*y + floatBpp*x);
+            auto rgbaB = static_cast<const float*>(colorPixmap.addr());
+            if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
+                return false;
+            }
+        }
     }
-
-    auto atA = std::function<AccessPixelFn>(
-        [](const char* floatBuffer, int /* x */, int /* y */) {
-            return reinterpret_cast<const float*>(floatBuffer);
-        });
-
-    auto atB = std::function<AccessPixelFn>(
-        [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
-            return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
-        });
-
-    return compare_pixels(pixmap.width(), pixmap.height(), floatA.get(), atA, floatB.get(), atB,
-                          tolRGBA, error);
+    return true;
 }
 
 void CheckSingleThreadedProxyRefs(skiatest::Reporter* reporter,
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
index f89eba8..e18e934 100644
--- a/tests/TransferPixelsTest.cpp
+++ b/tests/TransferPixelsTest.cpp
@@ -42,7 +42,8 @@
             uint32_t srcPixel = GrColorPackRGBA(r, g, 0xff - r, 0xff - g);
             GrImageInfo srcInfo(GrColorType::kRGBA_8888, kUnpremul_SkAlphaType, nullptr, 1, 1);
             GrImageInfo dstInfo(dstType, kUnpremul_SkAlphaType, nullptr, 1, 1);
-            GrConvertPixels(dstInfo, dstLocation(i, j), dstBpp, srcInfo, &srcPixel, 4);
+            GrConvertPixels(GrPixmap(dstInfo, dstLocation(i, j), dstBpp),
+                            GrPixmap(srcInfo,         &srcPixel,      4));
         }
     }
 }
@@ -88,8 +89,8 @@
         GrImageInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
         GrImageInfo 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 GrConvertPixels(GrPixmap(dstInfo,             dst,    rowBytes),
+                               GrPixmap(tmpInfo, tmpPixels.get(), tmpRowBytes));
     }
     return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes);
 }
diff --git a/tools/flags/CommonFlagsConfig.cpp b/tools/flags/CommonFlagsConfig.cpp
index c4df223..d949548 100644
--- a/tools/flags/CommonFlagsConfig.cpp
+++ b/tools/flags/CommonFlagsConfig.cpp
@@ -5,10 +5,12 @@
  * found in the LICENSE file.
  */
 
+#include "tools/flags/CommonFlagsConfig.h"
+
 #include "include/core/SkImageInfo.h"
+#include "include/core/SkSurfaceProps.h"
 #include "include/private/SkTHash.h"
 #include "src/core/SkColorSpacePriv.h"
-#include "tools/flags/CommonFlagsConfig.h"
 
 #include <stdlib.h>
 
diff --git a/tools/gpu/ProxyUtils.cpp b/tools/gpu/ProxyUtils.cpp
index bf1d7b3..f3344e6 100644
--- a/tools/gpu/ProxyUtils.cpp
+++ b/tools/gpu/ProxyUtils.cpp
@@ -52,7 +52,7 @@
 GrSurfaceProxyView MakeTextureProxyViewFromData(GrDirectContext* dContext,
                                                 GrRenderable renderable,
                                                 GrSurfaceOrigin origin,
-                                                GrPixmap pixmap) {
+                                                GrCPixmap pixmap) {
     if (dContext->abandoned()) {
         return {};
     }
diff --git a/tools/gpu/ProxyUtils.h b/tools/gpu/ProxyUtils.h
index 7ce0122..c4db536 100644
--- a/tools/gpu/ProxyUtils.h
+++ b/tools/gpu/ProxyUtils.h
@@ -15,7 +15,7 @@
 
 class GrDirectContext;
 class GrProgramInfo;
-class GrPixmap;
+class GrCPixmap;
 
 namespace sk_gpu_test {
 
@@ -26,7 +26,7 @@
 GrSurfaceProxyView MakeTextureProxyViewFromData(GrDirectContext*,
                                                 GrRenderable,
                                                 GrSurfaceOrigin,
-                                                GrPixmap pixmap);
+                                                GrCPixmap pixmap);
 
 GrProgramInfo* CreateProgramInfo(const GrCaps*,
                                  SkArenaAlloc*,
diff --git a/tools/gpu/gl/angle/GLTestContext_angle.cpp b/tools/gpu/gl/angle/GLTestContext_angle.cpp
index 13052fd..202c7ff 100644
--- a/tools/gpu/gl/angle/GLTestContext_angle.cpp
+++ b/tools/gpu/gl/angle/GLTestContext_angle.cpp
@@ -5,6 +5,8 @@
  * found in the LICENSE file.
  */
 
+#include "tools/gpu/gl/angle/GLTestContext_angle.h"
+
 #include "include/core/SkTime.h"
 #include "include/gpu/gl/GrGLAssembleInterface.h"
 #include "include/gpu/gl/GrGLInterface.h"
@@ -12,9 +14,10 @@
 #include "src/gpu/gl/GrGLDefines.h"
 #include "src/gpu/gl/GrGLUtil.h"
 #include "src/ports/SkOSLibrary.h"
-#include "tools/gpu/gl/angle/GLTestContext_angle.h"
 #include "third_party/externals/angle2/include/platform/Platform.h"
 
+#include <vector>
+
 #define EGL_EGL_PROTOTYPES 1
 #include <EGL/egl.h>
 #include <EGL/eglext.h>