Move GrContextPriv methods to their own .cpp file

Centralize these for my sanity. Most will also be parceled out to other contexts.

Change-Id: If0e7e98bcf66c4d8a3391f9b04e643ccc91af4ad
Reviewed-on: https://skia-review.googlesource.com/c/189488
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 7701011..9bf044d 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -7,26 +7,17 @@
 
 #include "GrContext.h"
 #include "GrBackendSemaphore.h"
-#include "GrClip.h"
-#include "GrContextOptions.h"
-#include "GrContextPriv.h"
 #include "GrDrawingManager.h"
 #include "GrGpu.h"
 #include "GrMemoryPool.h"
+#include "GrPathRendererChain.h"
 #include "GrProxyProvider.h"
-#include "GrRenderTargetContext.h"
 #include "GrRenderTargetProxy.h"
 #include "GrResourceCache.h"
 #include "GrResourceProvider.h"
 #include "GrSemaphore.h"
 #include "GrSoftwarePathRenderer.h"
-#include "GrSurfaceContext.h"
-#include "GrSurfacePriv.h"
-#include "GrSurfaceProxyPriv.h"
-#include "GrTexture.h"
-#include "GrTextureContext.h"
 #include "GrTracing.h"
-#include "SkAutoPixmapStorage.h"
 #include "SkDeferredDisplayList.h"
 #include "SkGr.h"
 #include "SkImageInfoPriv.h"
@@ -38,23 +29,18 @@
 #include "effects/GrSkSLFP.h"
 #include "ccpr/GrCoverageCountingPathRenderer.h"
 #include "text/GrTextBlobCache.h"
+#include "text/GrTextContext.h"
 #include <atomic>
 #include <unordered_map>
 
 #define ASSERT_OWNED_PROXY(P) \
     SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this)
-#define ASSERT_OWNED_PROXY_PRIV(P) \
-    SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == fContext)
 
 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
 #define ASSERT_SINGLE_OWNER \
     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
-#define ASSERT_SINGLE_OWNER_PRIV \
-    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
-#define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
-#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -315,14 +301,6 @@
     return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores);
 }
 
-void GrContextPriv::flush(GrSurfaceProxy* proxy) {
-    ASSERT_SINGLE_OWNER_PRIV
-    RETURN_IF_ABANDONED_PRIV
-    ASSERT_OWNED_PROXY_PRIV(proxy);
-
-    fContext->fDrawingManager->flush(proxy);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrContext::storeVkPipelineCacheData() {
@@ -333,748 +311,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-// TODO: This will be removed when GrSurfaceContexts are aware of their color types.
-// (skbug.com/6718)
-static bool valid_premul_config(GrPixelConfig config) {
-    switch (config) {
-        case kUnknown_GrPixelConfig:            return false;
-        case kAlpha_8_GrPixelConfig:            return false;
-        case kGray_8_GrPixelConfig:             return false;
-        case kRGB_565_GrPixelConfig:            return false;
-        case kRGBA_4444_GrPixelConfig:          return true;
-        case kRGBA_8888_GrPixelConfig:          return true;
-        case kRGB_888_GrPixelConfig:            return false;
-        case kRG_88_GrPixelConfig:              return false;
-        case kBGRA_8888_GrPixelConfig:          return true;
-        case kSRGBA_8888_GrPixelConfig:         return true;
-        case kSBGRA_8888_GrPixelConfig:         return true;
-        case kRGBA_1010102_GrPixelConfig:       return true;
-        case kRGBA_float_GrPixelConfig:         return true;
-        case kRG_float_GrPixelConfig:           return false;
-        case kAlpha_half_GrPixelConfig:         return false;
-        case kRGBA_half_GrPixelConfig:          return true;
-        case kRGB_ETC1_GrPixelConfig:           return false;
-        case kAlpha_8_as_Alpha_GrPixelConfig:   return false;
-        case kAlpha_8_as_Red_GrPixelConfig:     return false;
-        case kAlpha_half_as_Red_GrPixelConfig:  return false;
-        case kGray_8_as_Lum_GrPixelConfig:      return false;
-        case kGray_8_as_Red_GrPixelConfig:      return false;
-    }
-    SK_ABORT("Invalid GrPixelConfig");
-    return false;
-}
-
-static bool valid_premul_color_type(GrColorType ct) {
-    switch (ct) {
-        case GrColorType::kUnknown:      return false;
-        case GrColorType::kAlpha_8:      return false;
-        case GrColorType::kRGB_565:      return false;
-        case GrColorType::kABGR_4444:    return true;
-        case GrColorType::kRGBA_8888:    return true;
-        case GrColorType::kRGB_888x:     return false;
-        case GrColorType::kRG_88:        return false;
-        case GrColorType::kBGRA_8888:    return true;
-        case GrColorType::kRGBA_1010102: return true;
-        case GrColorType::kGray_8:       return false;
-        case GrColorType::kAlpha_F16:    return false;
-        case GrColorType::kRGBA_F16:     return true;
-        case GrColorType::kRG_F32:       return false;
-        case GrColorType::kRGBA_F32:     return true;
-        case GrColorType::kRGB_ETC1:     return false;
-    }
-    SK_ABORT("Invalid GrColorType");
-    return false;
-}
-
-static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig,
-                                   bool premulConversion) {
-    // We only allow premul <-> unpremul conversions for some formats
-    if (premulConversion &&
-        (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) {
-        return false;
-    }
-    return true;
-}
-
-bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width,
-                                       int height, GrColorType srcColorType,
-                                       SkColorSpace* srcColorSpace, const void* buffer,
-                                       size_t rowBytes, uint32_t pixelOpsFlags) {
-    ASSERT_SINGLE_OWNER_PRIV
-    RETURN_FALSE_IF_ABANDONED_PRIV
-    SkASSERT(dst);
-    SkASSERT(buffer);
-    ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
-    GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
-
-    if (GrColorType::kUnknown == srcColorType) {
-        return false;
-    }
-
-    if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
-        return false;
-    }
-
-    GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
-    GrSurface* dstSurface = dstProxy->peekSurface();
-
-    if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
-                                               GrColorTypeBytesPerPixel(srcColorType), &left, &top,
-                                               &width, &height, &buffer, &rowBytes)) {
-        return false;
-    }
-
-    // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type.
-    bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
-
-    // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
-    // that are premultiplied on the GPU. This is kept as narrow as possible for now.
-    bool canvas2DFastPath =
-            !fContext->priv().caps()->avoidWritePixelsFastPath() &&
-            premul &&
-            !dst->colorSpaceInfo().colorSpace() &&
-            (srcColorType == GrColorType::kRGBA_8888 || srcColorType == GrColorType::kBGRA_8888) &&
-            SkToBool(dst->asRenderTargetContext()) &&
-            (dstProxy->config() == kRGBA_8888_GrPixelConfig ||
-             dstProxy->config() == kBGRA_8888_GrPixelConfig) &&
-            !(pixelOpsFlags & kDontFlush_PixelOpsFlag) &&
-            fContext->priv().caps()->isConfigTexturable(kRGBA_8888_GrPixelConfig) &&
-            fContext->validPMUPMConversionExists();
-
-    const GrCaps* caps = this->caps();
-    if (!caps->surfaceSupportsWritePixels(dstSurface) ||
-        canvas2DFastPath) {
-        // We don't expect callers that are skipping flushes to require an intermediate draw.
-        SkASSERT(!(pixelOpsFlags & kDontFlush_PixelOpsFlag));
-        if (pixelOpsFlags & kDontFlush_PixelOpsFlag) {
-            return false;
-        }
-
-        GrSurfaceDesc desc;
-        desc.fWidth = width;
-        desc.fHeight = height;
-        desc.fSampleCnt = 1;
-
-        GrBackendFormat format;
-        if (canvas2DFastPath) {
-            desc.fConfig = kRGBA_8888_GrPixelConfig;
-            format =
-              fContext->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
-        } else {
-            desc.fConfig =  dstProxy->config();
-            format = dstProxy->backendFormat().makeTexture2D();
-            if (!format.isValid()) {
-                return false;
-            }
-        }
-
-        auto tempProxy = this->proxyProvider()->createProxy(
-                format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
-        if (!tempProxy) {
-            return false;
-        }
-        auto tempCtx = this->drawingManager()->makeTextureContext(
-                tempProxy, dst->colorSpaceInfo().refColorSpace());
-        if (!tempCtx) {
-            return false;
-        }
-        uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags;
-        // In the fast path we always write the srcData to the temp context as though it were RGBA.
-        // When the data is really BGRA the write will cause the R and B channels to be swapped in
-        // the intermediate surface which gets corrected by a swizzle effect when drawing to the
-        // dst.
-        auto tmpColorType = canvas2DFastPath ? GrColorType::kRGBA_8888 : srcColorType;
-        if (!this->writeSurfacePixels(tempCtx.get(), 0, 0, width, height, tmpColorType,
-                                      srcColorSpace, buffer, rowBytes, flags)) {
-            return false;
-        }
-        if (canvas2DFastPath) {
-            GrPaint paint;
-            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-            auto fp = fContext->createUPMToPMEffect(
-                    GrSimpleTextureEffect::Make(std::move(tempProxy), SkMatrix::I()));
-            if (srcColorType == GrColorType::kBGRA_8888) {
-                fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
-            }
-            if (!fp) {
-                return false;
-            }
-            paint.addColorFragmentProcessor(std::move(fp));
-            dst->asRenderTargetContext()->fillRectToRect(
-                    GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
-                    SkRect::MakeXYWH(left, top, width, height), SkRect::MakeWH(width, height));
-            return true;
-        } else {
-            return dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top});
-        }
-    }
-
-    bool convert = premul;
-
-    if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
-        return false;
-    }
-
-    GrColorType allowedColorType = fContext->priv().caps()->supportedWritePixelsColorType(
-            dstProxy->config(), srcColorType);
-    convert = convert || (srcColorType != allowedColorType);
-
-    if (!dst->colorSpaceInfo().colorSpace()) {
-        // "Legacy" mode - no color space conversions.
-        srcColorSpace = nullptr;
-    }
-    convert = convert || !SkColorSpace::Equals(srcColorSpace, dst->colorSpaceInfo().colorSpace());
-
-    std::unique_ptr<char[]> tempBuffer;
-    if (convert) {
-        auto srcSkColorType = GrColorTypeToSkColorType(srcColorType);
-        auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType);
-        if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
-            return false;
-        }
-        auto srcAlphaType = SkColorTypeIsAlwaysOpaque(srcSkColorType)
-                ? kOpaque_SkAlphaType
-                : (premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType);
-        SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType,
-                                       sk_ref_sp(srcColorSpace)),
-                     buffer, rowBytes);
-        auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType,
-                                           dst->colorSpaceInfo().refColorSpace());
-        auto size = tempSrcII.computeMinByteSize();
-        if (!size) {
-            return false;
-        }
-        tempBuffer.reset(new char[size]);
-        SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes());
-        if (!src.readPixels(tempSrc)) {
-            return false;
-        }
-        srcColorType = allowedColorType;
-        buffer = tempSrc.addr();
-        rowBytes = tempSrc.rowBytes();
-        if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
-            std::unique_ptr<char[]> row(new char[rowBytes]);
-            for (int y = 0; y < height / 2; ++y) {
-                memcpy(row.get(), tempSrc.addr(0, y), rowBytes);
-                memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes);
-                memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes);
-            }
-            top = dstSurface->height() - top - height;
-        }
-    } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
-        size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width;
-        tempBuffer.reset(new char[trimRowBytes * height]);
-        char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1);
-        const char* src = reinterpret_cast<const char*>(buffer);
-        for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) {
-            memcpy(dst, src, trimRowBytes);
-        }
-        buffer = tempBuffer.get();
-        rowBytes = trimRowBytes;
-        top = dstSurface->height() - top - height;
-    }
-
-    if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
-        this->flush(nullptr);  // MDB TODO: tighten this
-    }
-
-    return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer,
-                                       rowBytes);
-}
-
-bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width,
-                                      int height, GrColorType dstColorType,
-                                      SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes,
-                                      uint32_t pixelOpsFlags) {
-    ASSERT_SINGLE_OWNER_PRIV
-    RETURN_FALSE_IF_ABANDONED_PRIV
-    SkASSERT(src);
-    SkASSERT(buffer);
-    ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
-    GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
-
-    SkASSERT(!(pixelOpsFlags & kDontFlush_PixelOpsFlag));
-    if (pixelOpsFlags & kDontFlush_PixelOpsFlag) {
-        return false;
-    }
-
-    // MDB TODO: delay this instantiation until later in the method
-    if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) {
-        return false;
-    }
-
-    GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
-    GrSurface* srcSurface = srcProxy->peekSurface();
-
-    if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
-                                              GrColorTypeBytesPerPixel(dstColorType), &left, &top,
-                                              &width, &height, &buffer, &rowBytes)) {
-        return false;
-    }
-
-    // TODO: Make GrSurfaceContext know its alpha type and pass dst buffer's alpha type.
-    bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
-
-    if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) {
-        return false;
-    }
-
-    // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't
-    // care so much about getImageData performance. However, in order to ensure putImageData/
-    // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary
-    // unpremul step to writeSurfacePixels's premul step (which is determined empirically in
-    // fContext->vaildaPMUPMConversionExists()).
-    bool canvas2DFastPath =
-            unpremul &&
-            !src->colorSpaceInfo().colorSpace() &&
-            (GrColorType::kRGBA_8888 == dstColorType || GrColorType::kBGRA_8888 == dstColorType) &&
-            SkToBool(srcProxy->asTextureProxy()) &&
-            (srcProxy->config() == kRGBA_8888_GrPixelConfig ||
-             srcProxy->config() == kBGRA_8888_GrPixelConfig) &&
-            fContext->priv().caps()->isConfigRenderable(kRGBA_8888_GrPixelConfig) &&
-            fContext->validPMUPMConversionExists();
-
-    if (!fContext->priv().caps()->surfaceSupportsReadPixels(srcSurface) ||
-        canvas2DFastPath) {
-        GrSurfaceDesc desc;
-        desc.fFlags = canvas2DFastPath ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
-        desc.fConfig = canvas2DFastPath ? kRGBA_8888_GrPixelConfig : srcProxy->config();
-        desc.fWidth = width;
-        desc.fHeight = height;
-        desc.fSampleCnt = 1;
-
-        GrBackendFormat format;
-        if (canvas2DFastPath) {
-            desc.fFlags = kRenderTarget_GrSurfaceFlag;
-            desc.fConfig = kRGBA_8888_GrPixelConfig;
-            format = this->caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
-        } else {
-            desc.fFlags = kNone_GrSurfaceFlags;
-            desc.fConfig = srcProxy->config();
-            format = srcProxy->backendFormat().makeTexture2D();
-            if (!format.isValid()) {
-                return false;
-            }
-        }
-
-        auto tempProxy = this->proxyProvider()->createProxy(
-                format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
-        if (!tempProxy) {
-            return false;
-        }
-        sk_sp<GrSurfaceContext> tempCtx;
-        if (canvas2DFastPath) {
-            tempCtx = this->drawingManager()->makeRenderTargetContext(std::move(tempProxy), nullptr,
-                                                                      nullptr);
-            SkASSERT(tempCtx->asRenderTargetContext());
-            tempCtx->asRenderTargetContext()->discard();
-        } else {
-            tempCtx = this->drawingManager()->makeTextureContext(
-                    std::move(tempProxy), src->colorSpaceInfo().refColorSpace());
-        }
-        if (!tempCtx) {
-            return false;
-        }
-        if (canvas2DFastPath) {
-            GrPaint paint;
-            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-            auto fp = fContext->createPMToUPMEffect(
-                    GrSimpleTextureEffect::Make(sk_ref_sp(srcProxy->asTextureProxy()),
-                                                SkMatrix::I()));
-            if (dstColorType == GrColorType::kBGRA_8888) {
-                fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
-                dstColorType = GrColorType::kRGBA_8888;
-            }
-            if (!fp) {
-                return false;
-            }
-            paint.addColorFragmentProcessor(std::move(fp));
-            tempCtx->asRenderTargetContext()->fillRectToRect(
-                    GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
-                    SkRect::MakeWH(width, height), SkRect::MakeXYWH(left, top, width, height));
-        } else if (!tempCtx->copy(srcProxy, SkIRect::MakeXYWH(left, top, width, height), {0, 0})) {
-            return false;
-        }
-        uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags;
-        return this->readSurfacePixels(tempCtx.get(), 0, 0, width, height, dstColorType,
-                                       dstColorSpace, buffer, rowBytes, flags);
-    }
-
-    bool convert = unpremul;
-
-    bool flip = srcProxy->origin() == kBottomLeft_GrSurfaceOrigin;
-    if (flip) {
-        top = srcSurface->height() - top - height;
-    }
-
-    GrColorType allowedColorType = fContext->priv().caps()->supportedReadPixelsColorType(
-            srcProxy->config(), dstColorType);
-    convert = convert || (dstColorType != allowedColorType);
-
-    if (!src->colorSpaceInfo().colorSpace()) {
-        // "Legacy" mode - no color space conversions.
-        dstColorSpace = nullptr;
-    }
-    convert = convert || !SkColorSpace::Equals(dstColorSpace, src->colorSpaceInfo().colorSpace());
-
-    SkAutoPixmapStorage tempPixmap;
-    SkPixmap finalPixmap;
-    if (convert) {
-        SkColorType srcSkColorType = GrColorTypeToSkColorType(allowedColorType);
-        SkColorType dstSkColorType = GrColorTypeToSkColorType(dstColorType);
-        bool srcAlwaysOpaque = SkColorTypeIsAlwaysOpaque(srcSkColorType);
-        bool dstAlwaysOpaque = SkColorTypeIsAlwaysOpaque(dstSkColorType);
-        if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
-            return false;
-        }
-        auto tempAT = srcAlwaysOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
-        auto tempII = SkImageInfo::Make(width, height, srcSkColorType, tempAT,
-                                        src->colorSpaceInfo().refColorSpace());
-        SkASSERT(!unpremul || !dstAlwaysOpaque);
-        auto finalAT = (srcAlwaysOpaque || dstAlwaysOpaque)
-                               ? kOpaque_SkAlphaType
-                               : unpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
-        auto finalII =
-                SkImageInfo::Make(width, height, dstSkColorType, finalAT, sk_ref_sp(dstColorSpace));
-        if (!SkImageInfoValidConversion(finalII, tempII)) {
-            return false;
-        }
-        if (!tempPixmap.tryAlloc(tempII)) {
-            return false;
-        }
-        finalPixmap.reset(finalII, buffer, rowBytes);
-        buffer = tempPixmap.writable_addr();
-        rowBytes = tempPixmap.rowBytes();
-        // Chrome msan bots require this.
-        sk_bzero(buffer, tempPixmap.computeByteSize());
-    }
-
-    if (srcSurface->surfacePriv().hasPendingWrite()) {
-        this->flush(nullptr);  // MDB TODO: tighten this
-    }
-
-    if (!fContext->fGpu->readPixels(srcSurface, left, top, width, height, allowedColorType, buffer,
-                                    rowBytes)) {
-        return false;
-    }
-
-    if (flip) {
-        size_t trimRowBytes = GrColorTypeBytesPerPixel(allowedColorType) * width;
-        std::unique_ptr<char[]> row(new char[trimRowBytes]);
-        char* upper = reinterpret_cast<char*>(buffer);
-        char* lower = reinterpret_cast<char*>(buffer) + (height - 1) * rowBytes;
-        for (int y = 0; y < height / 2; ++y, upper += rowBytes, lower -= rowBytes) {
-            memcpy(row.get(), upper, trimRowBytes);
-            memcpy(upper, lower, trimRowBytes);
-            memcpy(lower, row.get(), trimRowBytes);
-        }
-    }
-    if (convert) {
-        if (!tempPixmap.readPixels(finalPixmap)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
-    ASSERT_SINGLE_OWNER_PRIV
-    RETURN_IF_ABANDONED_PRIV
-    SkASSERT(proxy);
-    ASSERT_OWNED_PROXY_PRIV(proxy);
-    fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
-}
-
-void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
-    ASSERT_SINGLE_OWNER_PRIV
-    RETURN_IF_ABANDONED_PRIV
-    SkASSERT(proxy);
-    ASSERT_OWNED_PROXY_PRIV(proxy);
-    if (proxy->priv().hasPendingWrite()) {
-        this->flush(proxy);
-    }
-}
-
-void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
-    ASSERT_SINGLE_OWNER_PRIV
-    RETURN_IF_ABANDONED_PRIV
-    SkASSERT(proxy);
-    ASSERT_OWNED_PROXY_PRIV(proxy);
-    if (proxy->priv().hasPendingIO()) {
-        this->flush(proxy);
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-sk_sp<GrOpMemoryPool> GrContextPriv::refOpMemoryPool() {
-    if (!fContext->fOpMemoryPool) {
-        // DDL TODO: should the size of the memory pool be decreased in DDL mode? CPU-side memory
-        // consumed in DDL mode vs. normal mode for a single skp might be a good metric of wasted
-        // memory.
-        fContext->fOpMemoryPool = sk_sp<GrOpMemoryPool>(new GrOpMemoryPool(16384, 16384));
-    }
-
-    SkASSERT(fContext->fOpMemoryPool);
-    return fContext->fOpMemoryPool;
-}
-
-GrOpMemoryPool* GrContextPriv::opMemoryPool() {
-    return this->refOpMemoryPool().get();
-}
-
-sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
-                                                                 sk_sp<SkColorSpace> colorSpace,
-                                                                 const SkSurfaceProps* props) {
-    ASSERT_SINGLE_OWNER_PRIV
-
-    if (proxy->asRenderTargetProxy()) {
-        return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
-                                                               std::move(colorSpace), props);
-    } else {
-        SkASSERT(proxy->asTextureProxy());
-        SkASSERT(!props);
-        return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
-    }
-}
-
-sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrBackendFormat& format,
-                                                                  const GrSurfaceDesc& dstDesc,
-                                                                  GrSurfaceOrigin origin,
-                                                                  GrMipMapped mipMapped,
-                                                                  SkBackingFit fit,
-                                                                  SkBudgeted isDstBudgeted,
-                                                                  sk_sp<SkColorSpace> colorSpace,
-                                                                  const SkSurfaceProps* props) {
-    sk_sp<GrTextureProxy> proxy;
-    if (GrMipMapped::kNo == mipMapped) {
-        proxy = this->proxyProvider()->createProxy(format, dstDesc, origin, fit, isDstBudgeted);
-    } else {
-        SkASSERT(SkBackingFit::kExact == fit);
-        proxy = this->proxyProvider()->createMipMapProxy(format, dstDesc, origin, isDstBudgeted);
-    }
-    if (!proxy) {
-        return nullptr;
-    }
-
-    sk_sp<GrSurfaceContext> sContext = this->makeWrappedSurfaceContext(std::move(proxy),
-                                                                       std::move(colorSpace),
-                                                                       props);
-    if (sContext && sContext->asRenderTargetContext()) {
-        sContext->asRenderTargetContext()->discard();
-    }
-
-    return sContext;
-}
-
-sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
-                                                                 GrSurfaceOrigin origin,
-                                                                 sk_sp<SkColorSpace> colorSpace) {
-    ASSERT_SINGLE_OWNER_PRIV
-
-    sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendTexture(
-            tex, origin, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType);
-    if (!proxy) {
-        return nullptr;
-    }
-
-    return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
-}
-
-sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
-                                                                   const GrBackendTexture& tex,
-                                                                   GrSurfaceOrigin origin,
-                                                                   int sampleCnt,
-                                                                   sk_sp<SkColorSpace> colorSpace,
-                                                                   const SkSurfaceProps* props,
-                                                                   ReleaseProc releaseProc,
-                                                                   ReleaseContext releaseCtx) {
-    ASSERT_SINGLE_OWNER_PRIV
-    SkASSERT(sampleCnt > 0);
-
-    sk_sp<GrTextureProxy> proxy(this->proxyProvider()->wrapRenderableBackendTexture(
-            tex, origin, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, releaseProc,
-            releaseCtx));
-    if (!proxy) {
-        return nullptr;
-    }
-
-    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
-                                                           std::move(colorSpace), props);
-}
-
-sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
-                                                const GrBackendRenderTarget& backendRT,
-                                                GrSurfaceOrigin origin,
-                                                sk_sp<SkColorSpace> colorSpace,
-                                                const SkSurfaceProps* surfaceProps,
-                                                ReleaseProc releaseProc,
-                                                ReleaseContext releaseCtx) {
-    ASSERT_SINGLE_OWNER_PRIV
-
-    sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendRenderTarget(
-            backendRT, origin, releaseProc, releaseCtx);
-    if (!proxy) {
-        return nullptr;
-    }
-
-    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
-                                                           std::move(colorSpace),
-                                                           surfaceProps);
-}
-
-sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
-                                                     const GrBackendTexture& tex,
-                                                     GrSurfaceOrigin origin,
-                                                     int sampleCnt,
-                                                     sk_sp<SkColorSpace> colorSpace,
-                                                     const SkSurfaceProps* props) {
-    ASSERT_SINGLE_OWNER_PRIV
-    SkASSERT(sampleCnt > 0);
-    sk_sp<GrSurfaceProxy> proxy(
-            this->proxyProvider()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt));
-    if (!proxy) {
-        return nullptr;
-    }
-
-    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
-                                                           std::move(colorSpace),
-                                                           props);
-}
-
-sk_sp<GrRenderTargetContext> GrContextPriv::makeVulkanSecondaryCBRenderTargetContext(
-        const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo, const SkSurfaceProps* props) {
-    ASSERT_SINGLE_OWNER_PRIV
-    sk_sp<GrSurfaceProxy> proxy(
-            this->proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo));
-    if (!proxy) {
-        return nullptr;
-    }
-
-    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
-                                                           imageInfo.refColorSpace(),
-                                                           props);
-}
-
-void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
-    fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
-}
-
-void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
-    fContext->fDrawingManager->moveOpListsToDDL(ddl);
-}
-
-void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
-                                       GrRenderTargetProxy* newDest) {
-    fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest);
-}
-
-static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
-    switch (config) {
-        case kAlpha_8_GrPixelConfig:
-        case kAlpha_8_as_Alpha_GrPixelConfig:
-        case kAlpha_8_as_Red_GrPixelConfig:
-        case kRGB_565_GrPixelConfig:
-        case kRGBA_4444_GrPixelConfig:
-        case kBGRA_8888_GrPixelConfig:
-        case kRGBA_1010102_GrPixelConfig:
-        case kRGBA_half_GrPixelConfig:
-            return kRGBA_8888_GrPixelConfig;
-        case kSBGRA_8888_GrPixelConfig:
-            return kSRGBA_8888_GrPixelConfig;
-        case kAlpha_half_GrPixelConfig:
-        case kAlpha_half_as_Red_GrPixelConfig:
-            return kRGBA_half_GrPixelConfig;
-        case kGray_8_GrPixelConfig:
-        case kGray_8_as_Lum_GrPixelConfig:
-        case kGray_8_as_Red_GrPixelConfig:
-            return kRGB_888_GrPixelConfig;
-        default:
-            return kUnknown_GrPixelConfig;
-    }
-}
-
-sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContextWithFallback(
-                                                                 const GrBackendFormat& format,
-                                                                 SkBackingFit fit,
-                                                                 int width, int height,
-                                                                 GrPixelConfig config,
-                                                                 sk_sp<SkColorSpace> colorSpace,
-                                                                 int sampleCnt,
-                                                                 GrMipMapped mipMapped,
-                                                                 GrSurfaceOrigin origin,
-                                                                 const SkSurfaceProps* surfaceProps,
-                                                                 SkBudgeted budgeted) {
-    GrBackendFormat localFormat = format;
-    SkASSERT(sampleCnt > 0);
-    if (0 == fContext->priv().caps()->getRenderTargetSampleCount(sampleCnt, config)) {
-        config = GrPixelConfigFallback(config);
-        // TODO: First we should be checking the getRenderTargetSampleCount from the GrBackendFormat
-        // and not GrPixelConfig. Besides that, we should implement the fallback in the caps, but
-        // for now we just convert the fallback pixel config to an SkColorType and then get the
-        // GrBackendFormat from that.
-        SkColorType colorType;
-        if (!GrPixelConfigToColorType(config, &colorType)) {
-            return nullptr;
-        }
-        localFormat = fContext->caps()->getBackendFormatFromColorType(colorType);
-    }
-
-    return this->makeDeferredRenderTargetContext(localFormat, fit, width, height, config,
-                                                 std::move(colorSpace), sampleCnt, mipMapped,
-                                                 origin, surfaceProps, budgeted);
-}
-
-sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContext(
-                                                        const GrBackendFormat& format,
-                                                        SkBackingFit fit,
-                                                        int width, int height,
-                                                        GrPixelConfig config,
-                                                        sk_sp<SkColorSpace> colorSpace,
-                                                        int sampleCnt,
-                                                        GrMipMapped mipMapped,
-                                                        GrSurfaceOrigin origin,
-                                                        const SkSurfaceProps* surfaceProps,
-                                                        SkBudgeted budgeted) {
-    SkASSERT(sampleCnt > 0);
-    if (fContext->abandoned()) {
-        return nullptr;
-    }
-
-    GrSurfaceDesc desc;
-    desc.fFlags = kRenderTarget_GrSurfaceFlag;
-    desc.fWidth = width;
-    desc.fHeight = height;
-    desc.fConfig = config;
-    desc.fSampleCnt = sampleCnt;
-
-    sk_sp<GrTextureProxy> rtp;
-    if (GrMipMapped::kNo == mipMapped) {
-        rtp = fContext->fProxyProvider->createProxy(format, desc, origin, fit, budgeted);
-    } else {
-        rtp = fContext->fProxyProvider->createMipMapProxy(format, desc, origin, budgeted);
-    }
-    if (!rtp) {
-        return nullptr;
-    }
-
-    sk_sp<GrRenderTargetContext> renderTargetContext(
-        fContext->fDrawingManager->makeRenderTargetContext(std::move(rtp),
-                                                           std::move(colorSpace),
-                                                           surfaceProps));
-    if (!renderTargetContext) {
-        return nullptr;
-    }
-
-    renderTargetContext->discard();
-
-    return renderTargetContext;
-}
-
-sk_sp<GrSkSLFPFactoryCache> GrContextPriv::fpFactoryCache() {
-    return fContext->fpFactoryCache();
-}
-
 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
         std::unique_ptr<GrFragmentProcessor> fp) {
     ASSERT_SINGLE_OWNER
@@ -1138,42 +374,3 @@
                                       fTextBlobCache->usedBytes());
 }
 
-//////////////////////////////////////////////////////////////////////////////
-#ifdef SK_ENABLE_DUMP_GPU
-#include "SkJSONWriter.h"
-SkString GrContextPriv::dump() const {
-    SkDynamicMemoryWStream stream;
-    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
-    writer.beginObject();
-
-    static const char* kBackendStr[] = {
-        "Metal",
-        "OpenGL",
-        "Vulkan",
-        "Mock",
-    };
-    GR_STATIC_ASSERT(0 == (unsigned)GrBackendApi::kMetal);
-    GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kOpenGL);
-    GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kVulkan);
-    GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kMock);
-    writer.appendString("backend", kBackendStr[(unsigned)fContext->backend()]);
-
-    writer.appendName("caps");
-    fContext->caps()->dumpJSON(&writer);
-
-    writer.appendName("gpu");
-    fContext->fGpu->dumpJSON(&writer);
-
-    // Flush JSON to the memory stream
-    writer.endObject();
-    writer.flush();
-
-    // Null terminate the JSON data in the memory stream
-    stream.write8(0);
-
-    // Allocate a string big enough to hold all the data, then copy out of the stream
-    SkString result(stream.bytesWritten());
-    stream.copyToAndReset(result.writable_str());
-    return result;
-}
-#endif
diff --git a/src/gpu/GrContextPriv.cpp b/src/gpu/GrContextPriv.cpp
new file mode 100644
index 0000000..c12ba76
--- /dev/null
+++ b/src/gpu/GrContextPriv.cpp
@@ -0,0 +1,898 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrContextPriv.h"
+
+#include "GrClip.h"
+#include "GrContextThreadSafeProxy.h"
+#include "GrContextThreadSafeProxyPriv.h"
+#include "GrDrawingManager.h"
+#include "GrGpu.h"
+#include "GrMemoryPool.h"
+#include "GrRenderTargetContext.h"
+#include "GrSkSLFPFactoryCache.h"
+#include "GrSurfacePriv.h"
+#include "GrTexture.h"
+#include "GrTextureContext.h"
+#include "SkAutoPixmapStorage.h"
+#include "SkImage_Base.h"
+#include "SkImage_Gpu.h"
+#include "SkGr.h"
+#include "text/GrTextBlobCache.h"
+
+#define ASSERT_OWNED_PROXY_PRIV(P) \
+    SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == fContext)
+#define ASSERT_SINGLE_OWNER_PRIV \
+    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
+#define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
+#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
+
+sk_sp<GrSkSLFPFactoryCache> GrContextPriv::fpFactoryCache() {
+    return fContext->fpFactoryCache();
+}
+
+sk_sp<GrOpMemoryPool> GrContextPriv::refOpMemoryPool() {
+    if (!fContext->fOpMemoryPool) {
+        // DDL TODO: should the size of the memory pool be decreased in DDL mode? CPU-side memory
+        // consumed in DDL mode vs. normal mode for a single skp might be a good metric of wasted
+        // memory.
+        fContext->fOpMemoryPool = sk_sp<GrOpMemoryPool>(new GrOpMemoryPool(16384, 16384));
+    }
+
+    SkASSERT(fContext->fOpMemoryPool);
+    return fContext->fOpMemoryPool;
+}
+
+GrOpMemoryPool* GrContextPriv::opMemoryPool() {
+    return this->refOpMemoryPool().get();
+}
+
+sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
+                                                                 sk_sp<SkColorSpace> colorSpace,
+                                                                 const SkSurfaceProps* props) {
+    ASSERT_SINGLE_OWNER_PRIV
+
+    if (proxy->asRenderTargetProxy()) {
+        return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+                                                               std::move(colorSpace), props);
+    } else {
+        SkASSERT(proxy->asTextureProxy());
+        SkASSERT(!props);
+        return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
+    }
+}
+
+sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrBackendFormat& format,
+                                                                  const GrSurfaceDesc& dstDesc,
+                                                                  GrSurfaceOrigin origin,
+                                                                  GrMipMapped mipMapped,
+                                                                  SkBackingFit fit,
+                                                                  SkBudgeted isDstBudgeted,
+                                                                  sk_sp<SkColorSpace> colorSpace,
+                                                                  const SkSurfaceProps* props) {
+    sk_sp<GrTextureProxy> proxy;
+    if (GrMipMapped::kNo == mipMapped) {
+        proxy = this->proxyProvider()->createProxy(format, dstDesc, origin, fit, isDstBudgeted);
+    } else {
+        SkASSERT(SkBackingFit::kExact == fit);
+        proxy = this->proxyProvider()->createMipMapProxy(format, dstDesc, origin, isDstBudgeted);
+    }
+    if (!proxy) {
+        return nullptr;
+    }
+
+    sk_sp<GrSurfaceContext> sContext = this->makeWrappedSurfaceContext(std::move(proxy),
+                                                                       std::move(colorSpace),
+                                                                       props);
+    if (sContext && sContext->asRenderTargetContext()) {
+        sContext->asRenderTargetContext()->discard();
+    }
+
+    return sContext;
+}
+
+sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
+                                                                 GrSurfaceOrigin origin,
+                                                                 sk_sp<SkColorSpace> colorSpace) {
+    ASSERT_SINGLE_OWNER_PRIV
+
+    sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendTexture(
+            tex, origin, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType);
+    if (!proxy) {
+        return nullptr;
+    }
+
+    return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
+}
+
+sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
+                                                                   const GrBackendTexture& tex,
+                                                                   GrSurfaceOrigin origin,
+                                                                   int sampleCnt,
+                                                                   sk_sp<SkColorSpace> colorSpace,
+                                                                   const SkSurfaceProps* props,
+                                                                   ReleaseProc releaseProc,
+                                                                   ReleaseContext releaseCtx) {
+    ASSERT_SINGLE_OWNER_PRIV
+    SkASSERT(sampleCnt > 0);
+
+    sk_sp<GrTextureProxy> proxy(this->proxyProvider()->wrapRenderableBackendTexture(
+            tex, origin, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, releaseProc,
+            releaseCtx));
+    if (!proxy) {
+        return nullptr;
+    }
+
+    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+                                                           std::move(colorSpace), props);
+}
+
+sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
+                                                const GrBackendRenderTarget& backendRT,
+                                                GrSurfaceOrigin origin,
+                                                sk_sp<SkColorSpace> colorSpace,
+                                                const SkSurfaceProps* surfaceProps,
+                                                ReleaseProc releaseProc,
+                                                ReleaseContext releaseCtx) {
+    ASSERT_SINGLE_OWNER_PRIV
+
+    sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendRenderTarget(
+            backendRT, origin, releaseProc, releaseCtx);
+    if (!proxy) {
+        return nullptr;
+    }
+
+    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+                                                           std::move(colorSpace),
+                                                           surfaceProps);
+}
+
+sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
+                                                     const GrBackendTexture& tex,
+                                                     GrSurfaceOrigin origin,
+                                                     int sampleCnt,
+                                                     sk_sp<SkColorSpace> colorSpace,
+                                                     const SkSurfaceProps* props) {
+    ASSERT_SINGLE_OWNER_PRIV
+    SkASSERT(sampleCnt > 0);
+    sk_sp<GrSurfaceProxy> proxy(
+            this->proxyProvider()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt));
+    if (!proxy) {
+        return nullptr;
+    }
+
+    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+                                                           std::move(colorSpace),
+                                                           props);
+}
+
+sk_sp<GrRenderTargetContext> GrContextPriv::makeVulkanSecondaryCBRenderTargetContext(
+        const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo, const SkSurfaceProps* props) {
+    ASSERT_SINGLE_OWNER_PRIV
+    sk_sp<GrSurfaceProxy> proxy(
+            this->proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo));
+    if (!proxy) {
+        return nullptr;
+    }
+
+    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+                                                           imageInfo.refColorSpace(),
+                                                           props);
+}
+
+void GrContextPriv::flush(GrSurfaceProxy* proxy) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_IF_ABANDONED_PRIV
+    ASSERT_OWNED_PROXY_PRIV(proxy);
+
+    fContext->fDrawingManager->flush(proxy);
+}
+
+void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
+    fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
+}
+
+void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_IF_ABANDONED_PRIV
+    SkASSERT(proxy);
+    ASSERT_OWNED_PROXY_PRIV(proxy);
+    if (proxy->priv().hasPendingWrite()) {
+        this->flush(proxy);
+    }
+}
+
+void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_IF_ABANDONED_PRIV
+    SkASSERT(proxy);
+    ASSERT_OWNED_PROXY_PRIV(proxy);
+    if (proxy->priv().hasPendingIO()) {
+        this->flush(proxy);
+    }
+}
+
+void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_IF_ABANDONED_PRIV
+    SkASSERT(proxy);
+    ASSERT_OWNED_PROXY_PRIV(proxy);
+    fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
+}
+
+static bool valid_premul_color_type(GrColorType ct) {
+    switch (ct) {
+        case GrColorType::kUnknown:      return false;
+        case GrColorType::kAlpha_8:      return false;
+        case GrColorType::kRGB_565:      return false;
+        case GrColorType::kABGR_4444:    return true;
+        case GrColorType::kRGBA_8888:    return true;
+        case GrColorType::kRGB_888x:     return false;
+        case GrColorType::kRG_88:        return false;
+        case GrColorType::kBGRA_8888:    return true;
+        case GrColorType::kRGBA_1010102: return true;
+        case GrColorType::kGray_8:       return false;
+        case GrColorType::kAlpha_F16:    return false;
+        case GrColorType::kRGBA_F16:     return true;
+        case GrColorType::kRG_F32:       return false;
+        case GrColorType::kRGBA_F32:     return true;
+        case GrColorType::kRGB_ETC1:     return false;
+    }
+    SK_ABORT("Invalid GrColorType");
+    return false;
+}
+
+// TODO: This will be removed when GrSurfaceContexts are aware of their color types.
+// (skbug.com/6718)
+static bool valid_premul_config(GrPixelConfig config) {
+    switch (config) {
+        case kUnknown_GrPixelConfig:            return false;
+        case kAlpha_8_GrPixelConfig:            return false;
+        case kGray_8_GrPixelConfig:             return false;
+        case kRGB_565_GrPixelConfig:            return false;
+        case kRGBA_4444_GrPixelConfig:          return true;
+        case kRGBA_8888_GrPixelConfig:          return true;
+        case kRGB_888_GrPixelConfig:            return false;
+        case kRG_88_GrPixelConfig:              return false;
+        case kBGRA_8888_GrPixelConfig:          return true;
+        case kSRGBA_8888_GrPixelConfig:         return true;
+        case kSBGRA_8888_GrPixelConfig:         return true;
+        case kRGBA_1010102_GrPixelConfig:       return true;
+        case kRGBA_float_GrPixelConfig:         return true;
+        case kRG_float_GrPixelConfig:           return false;
+        case kAlpha_half_GrPixelConfig:         return false;
+        case kRGBA_half_GrPixelConfig:          return true;
+        case kRGB_ETC1_GrPixelConfig:           return false;
+        case kAlpha_8_as_Alpha_GrPixelConfig:   return false;
+        case kAlpha_8_as_Red_GrPixelConfig:     return false;
+        case kAlpha_half_as_Red_GrPixelConfig:  return false;
+        case kGray_8_as_Lum_GrPixelConfig:      return false;
+        case kGray_8_as_Red_GrPixelConfig:      return false;
+    }
+    SK_ABORT("Invalid GrPixelConfig");
+    return false;
+}
+
+static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig,
+                                   bool premulConversion) {
+    // We only allow premul <-> unpremul conversions for some formats
+    if (premulConversion &&
+        (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) {
+        return false;
+    }
+    return true;
+}
+
+bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width,
+                                      int height, GrColorType dstColorType,
+                                      SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes,
+                                      uint32_t pixelOpsFlags) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_FALSE_IF_ABANDONED_PRIV
+    SkASSERT(src);
+    SkASSERT(buffer);
+    ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
+
+    SkASSERT(!(pixelOpsFlags & kDontFlush_PixelOpsFlag));
+    if (pixelOpsFlags & kDontFlush_PixelOpsFlag) {
+        return false;
+    }
+
+    // MDB TODO: delay this instantiation until later in the method
+    if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) {
+        return false;
+    }
+
+    GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
+    GrSurface* srcSurface = srcProxy->peekSurface();
+
+    if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
+                                              GrColorTypeBytesPerPixel(dstColorType), &left, &top,
+                                              &width, &height, &buffer, &rowBytes)) {
+        return false;
+    }
+
+    // TODO: Make GrSurfaceContext know its alpha type and pass dst buffer's alpha type.
+    bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
+
+    if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) {
+        return false;
+    }
+
+    // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't
+    // care so much about getImageData performance. However, in order to ensure putImageData/
+    // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary
+    // unpremul step to writeSurfacePixels's premul step (which is determined empirically in
+    // fContext->vaildaPMUPMConversionExists()).
+    bool canvas2DFastPath =
+            unpremul &&
+            !src->colorSpaceInfo().colorSpace() &&
+            (GrColorType::kRGBA_8888 == dstColorType || GrColorType::kBGRA_8888 == dstColorType) &&
+            SkToBool(srcProxy->asTextureProxy()) &&
+            (srcProxy->config() == kRGBA_8888_GrPixelConfig ||
+             srcProxy->config() == kBGRA_8888_GrPixelConfig) &&
+            fContext->priv().caps()->isConfigRenderable(kRGBA_8888_GrPixelConfig) &&
+            fContext->validPMUPMConversionExists();
+
+    if (!fContext->priv().caps()->surfaceSupportsReadPixels(srcSurface) ||
+        canvas2DFastPath) {
+        GrSurfaceDesc desc;
+        desc.fFlags = canvas2DFastPath ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
+        desc.fConfig = canvas2DFastPath ? kRGBA_8888_GrPixelConfig : srcProxy->config();
+        desc.fWidth = width;
+        desc.fHeight = height;
+        desc.fSampleCnt = 1;
+
+        GrBackendFormat format;
+        if (canvas2DFastPath) {
+            desc.fFlags = kRenderTarget_GrSurfaceFlag;
+            desc.fConfig = kRGBA_8888_GrPixelConfig;
+            format = this->caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
+        } else {
+            desc.fFlags = kNone_GrSurfaceFlags;
+            desc.fConfig = srcProxy->config();
+            format = srcProxy->backendFormat().makeTexture2D();
+            if (!format.isValid()) {
+                return false;
+            }
+        }
+
+        auto tempProxy = this->proxyProvider()->createProxy(
+                format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
+        if (!tempProxy) {
+            return false;
+        }
+        sk_sp<GrSurfaceContext> tempCtx;
+        if (canvas2DFastPath) {
+            tempCtx = this->drawingManager()->makeRenderTargetContext(std::move(tempProxy), nullptr,
+                                                                      nullptr);
+            SkASSERT(tempCtx->asRenderTargetContext());
+            tempCtx->asRenderTargetContext()->discard();
+        } else {
+            tempCtx = this->drawingManager()->makeTextureContext(
+                    std::move(tempProxy), src->colorSpaceInfo().refColorSpace());
+        }
+        if (!tempCtx) {
+            return false;
+        }
+        if (canvas2DFastPath) {
+            GrPaint paint;
+            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+            auto fp = fContext->createPMToUPMEffect(
+                    GrSimpleTextureEffect::Make(sk_ref_sp(srcProxy->asTextureProxy()),
+                                                SkMatrix::I()));
+            if (dstColorType == GrColorType::kBGRA_8888) {
+                fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
+                dstColorType = GrColorType::kRGBA_8888;
+            }
+            if (!fp) {
+                return false;
+            }
+            paint.addColorFragmentProcessor(std::move(fp));
+            tempCtx->asRenderTargetContext()->fillRectToRect(
+                    GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
+                    SkRect::MakeWH(width, height), SkRect::MakeXYWH(left, top, width, height));
+        } else if (!tempCtx->copy(srcProxy, SkIRect::MakeXYWH(left, top, width, height), {0, 0})) {
+            return false;
+        }
+        uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags;
+        return this->readSurfacePixels(tempCtx.get(), 0, 0, width, height, dstColorType,
+                                       dstColorSpace, buffer, rowBytes, flags);
+    }
+
+    bool convert = unpremul;
+
+    bool flip = srcProxy->origin() == kBottomLeft_GrSurfaceOrigin;
+    if (flip) {
+        top = srcSurface->height() - top - height;
+    }
+
+    GrColorType allowedColorType = fContext->priv().caps()->supportedReadPixelsColorType(
+            srcProxy->config(), dstColorType);
+    convert = convert || (dstColorType != allowedColorType);
+
+    if (!src->colorSpaceInfo().colorSpace()) {
+        // "Legacy" mode - no color space conversions.
+        dstColorSpace = nullptr;
+    }
+    convert = convert || !SkColorSpace::Equals(dstColorSpace, src->colorSpaceInfo().colorSpace());
+
+    SkAutoPixmapStorage tempPixmap;
+    SkPixmap finalPixmap;
+    if (convert) {
+        SkColorType srcSkColorType = GrColorTypeToSkColorType(allowedColorType);
+        SkColorType dstSkColorType = GrColorTypeToSkColorType(dstColorType);
+        bool srcAlwaysOpaque = SkColorTypeIsAlwaysOpaque(srcSkColorType);
+        bool dstAlwaysOpaque = SkColorTypeIsAlwaysOpaque(dstSkColorType);
+        if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
+            return false;
+        }
+        auto tempAT = srcAlwaysOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
+        auto tempII = SkImageInfo::Make(width, height, srcSkColorType, tempAT,
+                                        src->colorSpaceInfo().refColorSpace());
+        SkASSERT(!unpremul || !dstAlwaysOpaque);
+        auto finalAT = (srcAlwaysOpaque || dstAlwaysOpaque)
+                               ? kOpaque_SkAlphaType
+                               : unpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
+        auto finalII =
+                SkImageInfo::Make(width, height, dstSkColorType, finalAT, sk_ref_sp(dstColorSpace));
+        if (!SkImageInfoValidConversion(finalII, tempII)) {
+            return false;
+        }
+        if (!tempPixmap.tryAlloc(tempII)) {
+            return false;
+        }
+        finalPixmap.reset(finalII, buffer, rowBytes);
+        buffer = tempPixmap.writable_addr();
+        rowBytes = tempPixmap.rowBytes();
+        // Chrome msan bots require this.
+        sk_bzero(buffer, tempPixmap.computeByteSize());
+    }
+
+    if (srcSurface->surfacePriv().hasPendingWrite()) {
+        this->flush(nullptr);  // MDB TODO: tighten this
+    }
+
+    if (!fContext->fGpu->readPixels(srcSurface, left, top, width, height, allowedColorType, buffer,
+                                    rowBytes)) {
+        return false;
+    }
+
+    if (flip) {
+        size_t trimRowBytes = GrColorTypeBytesPerPixel(allowedColorType) * width;
+        std::unique_ptr<char[]> row(new char[trimRowBytes]);
+        char* upper = reinterpret_cast<char*>(buffer);
+        char* lower = reinterpret_cast<char*>(buffer) + (height - 1) * rowBytes;
+        for (int y = 0; y < height / 2; ++y, upper += rowBytes, lower -= rowBytes) {
+            memcpy(row.get(), upper, trimRowBytes);
+            memcpy(upper, lower, trimRowBytes);
+            memcpy(lower, row.get(), trimRowBytes);
+        }
+    }
+    if (convert) {
+        if (!tempPixmap.readPixels(finalPixmap)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width,
+                                       int height, GrColorType srcColorType,
+                                       SkColorSpace* srcColorSpace, const void* buffer,
+                                       size_t rowBytes, uint32_t pixelOpsFlags) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_FALSE_IF_ABANDONED_PRIV
+    SkASSERT(dst);
+    SkASSERT(buffer);
+    ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
+
+    if (GrColorType::kUnknown == srcColorType) {
+        return false;
+    }
+
+    if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
+        return false;
+    }
+
+    GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
+    GrSurface* dstSurface = dstProxy->peekSurface();
+
+    if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
+                                               GrColorTypeBytesPerPixel(srcColorType), &left, &top,
+                                               &width, &height, &buffer, &rowBytes)) {
+        return false;
+    }
+
+    // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type.
+    bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
+
+    // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
+    // that are premultiplied on the GPU. This is kept as narrow as possible for now.
+    bool canvas2DFastPath =
+            !fContext->priv().caps()->avoidWritePixelsFastPath() &&
+            premul &&
+            !dst->colorSpaceInfo().colorSpace() &&
+            (srcColorType == GrColorType::kRGBA_8888 || srcColorType == GrColorType::kBGRA_8888) &&
+            SkToBool(dst->asRenderTargetContext()) &&
+            (dstProxy->config() == kRGBA_8888_GrPixelConfig ||
+             dstProxy->config() == kBGRA_8888_GrPixelConfig) &&
+            !(pixelOpsFlags & kDontFlush_PixelOpsFlag) &&
+            fContext->priv().caps()->isConfigTexturable(kRGBA_8888_GrPixelConfig) &&
+            fContext->validPMUPMConversionExists();
+
+    const GrCaps* caps = this->caps();
+    if (!caps->surfaceSupportsWritePixels(dstSurface) ||
+        canvas2DFastPath) {
+        // We don't expect callers that are skipping flushes to require an intermediate draw.
+        SkASSERT(!(pixelOpsFlags & kDontFlush_PixelOpsFlag));
+        if (pixelOpsFlags & kDontFlush_PixelOpsFlag) {
+            return false;
+        }
+
+        GrSurfaceDesc desc;
+        desc.fWidth = width;
+        desc.fHeight = height;
+        desc.fSampleCnt = 1;
+
+        GrBackendFormat format;
+        if (canvas2DFastPath) {
+            desc.fConfig = kRGBA_8888_GrPixelConfig;
+            format =
+              fContext->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
+        } else {
+            desc.fConfig =  dstProxy->config();
+            format = dstProxy->backendFormat().makeTexture2D();
+            if (!format.isValid()) {
+                return false;
+            }
+        }
+
+        auto tempProxy = this->proxyProvider()->createProxy(
+                format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
+        if (!tempProxy) {
+            return false;
+        }
+        auto tempCtx = this->drawingManager()->makeTextureContext(
+                tempProxy, dst->colorSpaceInfo().refColorSpace());
+        if (!tempCtx) {
+            return false;
+        }
+        uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags;
+        // In the fast path we always write the srcData to the temp context as though it were RGBA.
+        // When the data is really BGRA the write will cause the R and B channels to be swapped in
+        // the intermediate surface which gets corrected by a swizzle effect when drawing to the
+        // dst.
+        auto tmpColorType = canvas2DFastPath ? GrColorType::kRGBA_8888 : srcColorType;
+        if (!this->writeSurfacePixels(tempCtx.get(), 0, 0, width, height, tmpColorType,
+                                      srcColorSpace, buffer, rowBytes, flags)) {
+            return false;
+        }
+        if (canvas2DFastPath) {
+            GrPaint paint;
+            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+            auto fp = fContext->createUPMToPMEffect(
+                    GrSimpleTextureEffect::Make(std::move(tempProxy), SkMatrix::I()));
+            if (srcColorType == GrColorType::kBGRA_8888) {
+                fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
+            }
+            if (!fp) {
+                return false;
+            }
+            paint.addColorFragmentProcessor(std::move(fp));
+            dst->asRenderTargetContext()->fillRectToRect(
+                    GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
+                    SkRect::MakeXYWH(left, top, width, height), SkRect::MakeWH(width, height));
+            return true;
+        } else {
+            return dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top});
+        }
+    }
+
+    bool convert = premul;
+
+    if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
+        return false;
+    }
+
+    GrColorType allowedColorType = fContext->priv().caps()->supportedWritePixelsColorType(
+            dstProxy->config(), srcColorType);
+    convert = convert || (srcColorType != allowedColorType);
+
+    if (!dst->colorSpaceInfo().colorSpace()) {
+        // "Legacy" mode - no color space conversions.
+        srcColorSpace = nullptr;
+    }
+    convert = convert || !SkColorSpace::Equals(srcColorSpace, dst->colorSpaceInfo().colorSpace());
+
+    std::unique_ptr<char[]> tempBuffer;
+    if (convert) {
+        auto srcSkColorType = GrColorTypeToSkColorType(srcColorType);
+        auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType);
+        if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
+            return false;
+        }
+        auto srcAlphaType = SkColorTypeIsAlwaysOpaque(srcSkColorType)
+                ? kOpaque_SkAlphaType
+                : (premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType);
+        SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType,
+                                       sk_ref_sp(srcColorSpace)),
+                     buffer, rowBytes);
+        auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType,
+                                           dst->colorSpaceInfo().refColorSpace());
+        auto size = tempSrcII.computeMinByteSize();
+        if (!size) {
+            return false;
+        }
+        tempBuffer.reset(new char[size]);
+        SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes());
+        if (!src.readPixels(tempSrc)) {
+            return false;
+        }
+        srcColorType = allowedColorType;
+        buffer = tempSrc.addr();
+        rowBytes = tempSrc.rowBytes();
+        if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
+            std::unique_ptr<char[]> row(new char[rowBytes]);
+            for (int y = 0; y < height / 2; ++y) {
+                memcpy(row.get(), tempSrc.addr(0, y), rowBytes);
+                memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes);
+                memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes);
+            }
+            top = dstSurface->height() - top - height;
+        }
+    } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
+        size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width;
+        tempBuffer.reset(new char[trimRowBytes * height]);
+        char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1);
+        const char* src = reinterpret_cast<const char*>(buffer);
+        for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) {
+            memcpy(dst, src, trimRowBytes);
+        }
+        buffer = tempBuffer.get();
+        rowBytes = trimRowBytes;
+        top = dstSurface->height() - top - height;
+    }
+
+    if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
+        this->flush(nullptr);  // MDB TODO: tighten this
+    }
+
+    return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer,
+                                       rowBytes);
+}
+
+void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
+    fContext->fDrawingManager->moveOpListsToDDL(ddl);
+}
+
+void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
+                                       GrRenderTargetProxy* newDest) {
+    fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest);
+}
+
+sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContext(
+                                                        const GrBackendFormat& format,
+                                                        SkBackingFit fit,
+                                                        int width, int height,
+                                                        GrPixelConfig config,
+                                                        sk_sp<SkColorSpace> colorSpace,
+                                                        int sampleCnt,
+                                                        GrMipMapped mipMapped,
+                                                        GrSurfaceOrigin origin,
+                                                        const SkSurfaceProps* surfaceProps,
+                                                        SkBudgeted budgeted) {
+    SkASSERT(sampleCnt > 0);
+    if (fContext->abandoned()) {
+        return nullptr;
+    }
+
+    GrSurfaceDesc desc;
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+    desc.fWidth = width;
+    desc.fHeight = height;
+    desc.fConfig = config;
+    desc.fSampleCnt = sampleCnt;
+
+    sk_sp<GrTextureProxy> rtp;
+    if (GrMipMapped::kNo == mipMapped) {
+        rtp = fContext->fProxyProvider->createProxy(format, desc, origin, fit, budgeted);
+    } else {
+        rtp = fContext->fProxyProvider->createMipMapProxy(format, desc, origin, budgeted);
+    }
+    if (!rtp) {
+        return nullptr;
+    }
+
+    sk_sp<GrRenderTargetContext> renderTargetContext(
+        fContext->fDrawingManager->makeRenderTargetContext(std::move(rtp),
+                                                           std::move(colorSpace),
+                                                           surfaceProps));
+    if (!renderTargetContext) {
+        return nullptr;
+    }
+
+    renderTargetContext->discard();
+
+    return renderTargetContext;
+}
+
+static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
+    switch (config) {
+        case kAlpha_8_GrPixelConfig:
+        case kAlpha_8_as_Alpha_GrPixelConfig:
+        case kAlpha_8_as_Red_GrPixelConfig:
+        case kRGB_565_GrPixelConfig:
+        case kRGBA_4444_GrPixelConfig:
+        case kBGRA_8888_GrPixelConfig:
+        case kRGBA_1010102_GrPixelConfig:
+        case kRGBA_half_GrPixelConfig:
+            return kRGBA_8888_GrPixelConfig;
+        case kSBGRA_8888_GrPixelConfig:
+            return kSRGBA_8888_GrPixelConfig;
+        case kAlpha_half_GrPixelConfig:
+        case kAlpha_half_as_Red_GrPixelConfig:
+            return kRGBA_half_GrPixelConfig;
+        case kGray_8_GrPixelConfig:
+        case kGray_8_as_Lum_GrPixelConfig:
+        case kGray_8_as_Red_GrPixelConfig:
+            return kRGB_888_GrPixelConfig;
+        default:
+            return kUnknown_GrPixelConfig;
+    }
+}
+
+sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContextWithFallback(
+                                                                 const GrBackendFormat& format,
+                                                                 SkBackingFit fit,
+                                                                 int width, int height,
+                                                                 GrPixelConfig config,
+                                                                 sk_sp<SkColorSpace> colorSpace,
+                                                                 int sampleCnt,
+                                                                 GrMipMapped mipMapped,
+                                                                 GrSurfaceOrigin origin,
+                                                                 const SkSurfaceProps* surfaceProps,
+                                                                 SkBudgeted budgeted) {
+    GrBackendFormat localFormat = format;
+    SkASSERT(sampleCnt > 0);
+    if (0 == fContext->priv().caps()->getRenderTargetSampleCount(sampleCnt, config)) {
+        config = GrPixelConfigFallback(config);
+        // TODO: First we should be checking the getRenderTargetSampleCount from the GrBackendFormat
+        // and not GrPixelConfig. Besides that, we should implement the fallback in the caps, but
+        // for now we just convert the fallback pixel config to an SkColorType and then get the
+        // GrBackendFormat from that.
+        SkColorType colorType;
+        if (!GrPixelConfigToColorType(config, &colorType)) {
+            return nullptr;
+        }
+        localFormat = fContext->caps()->getBackendFormatFromColorType(colorType);
+    }
+
+    return this->makeDeferredRenderTargetContext(localFormat, fit, width, height, config,
+                                                 std::move(colorSpace), sampleCnt, mipMapped,
+                                                 origin, surfaceProps, budgeted);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+#ifdef SK_ENABLE_DUMP_GPU
+#include "SkJSONWriter.h"
+SkString GrContextPriv::dump() const {
+    SkDynamicMemoryWStream stream;
+    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
+    writer.beginObject();
+
+    static const char* kBackendStr[] = {
+        "Metal",
+        "OpenGL",
+        "Vulkan",
+        "Mock",
+    };
+    GR_STATIC_ASSERT(0 == (unsigned)GrBackendApi::kMetal);
+    GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kOpenGL);
+    GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kVulkan);
+    GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kMock);
+    writer.appendString("backend", kBackendStr[(unsigned)fContext->backend()]);
+
+    writer.appendName("caps");
+    fContext->caps()->dumpJSON(&writer);
+
+    writer.appendName("gpu");
+    fContext->fGpu->dumpJSON(&writer);
+
+    // Flush JSON to the memory stream
+    writer.endObject();
+    writer.flush();
+
+    // Null terminate the JSON data in the memory stream
+    stream.write8(0);
+
+    // Allocate a string big enough to hold all the data, then copy out of the stream
+    SkString result(stream.bytesWritten());
+    stream.copyToAndReset(result.writable_str());
+    return result;
+}
+#endif
+
+#if GR_TEST_UTILS
+void GrContextPriv::resetGpuStats() const {
+#if GR_GPU_STATS
+    fContext->fGpu->stats()->reset();
+#endif
+}
+
+void GrContextPriv::dumpCacheStats(SkString* out) const {
+#if GR_CACHE_STATS
+    fContext->fResourceCache->dumpStats(out);
+#endif
+}
+
+void GrContextPriv::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys,
+                                                SkTArray<double>* values) const {
+#if GR_CACHE_STATS
+    fContext->fResourceCache->dumpStatsKeyValuePairs(keys, values);
+#endif
+}
+
+void GrContextPriv::printCacheStats() const {
+    SkString out;
+    this->dumpCacheStats(&out);
+    SkDebugf("%s", out.c_str());
+}
+
+void GrContextPriv::dumpGpuStats(SkString* out) const {
+#if GR_GPU_STATS
+    return fContext->fGpu->stats()->dump(out);
+#endif
+}
+
+void GrContextPriv::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys,
+                                              SkTArray<double>* values) const {
+#if GR_GPU_STATS
+    return fContext->fGpu->stats()->dumpKeyValuePairs(keys, values);
+#endif
+}
+
+void GrContextPriv::printGpuStats() const {
+    SkString out;
+    this->dumpGpuStats(&out);
+    SkDebugf("%s", out.c_str());
+}
+
+void GrContextPriv::testingOnly_setTextBlobCacheLimit(size_t bytes) {
+    fContext->fTextBlobCache->setBudget(bytes);
+}
+
+sk_sp<SkImage> GrContextPriv::testingOnly_getFontAtlasImage(GrMaskFormat format, unsigned int index) {
+    auto atlasManager = this->getAtlasManager();
+    if (!atlasManager) {
+        return nullptr;
+    }
+
+    unsigned int numActiveProxies;
+    const sk_sp<GrTextureProxy>* proxies = atlasManager->getProxies(format, &numActiveProxies);
+    if (index >= numActiveProxies || !proxies || !proxies[index]) {
+        return nullptr;
+    }
+
+    SkASSERT(proxies[index]->priv().isExact());
+    sk_sp<SkImage> image(new SkImage_Gpu(sk_ref_sp(fContext), kNeedNewImageUniqueID,
+                                         kPremul_SkAlphaType, proxies[index], nullptr));
+    return image;
+}
+
+void GrContextPriv::testingOnly_purgeAllUnlockedResources() {
+    fContext->fResourceCache->purgeAllUnlocked();
+}
+
+void GrContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject* cb) {
+    fContext->flush();
+    fContext->fDrawingManager->testingOnly_removeOnFlushCallbackObject(cb);
+}
+#endif
+
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index 5b36351..5b3c05e 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -118,8 +118,6 @@
      */
     void addOnFlushCallbackObject(GrOnFlushCallbackObject*);
 
-    void testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject*);
-
     /**
      * After this returns any pending writes to the surface will have been issued to the
      * backend 3D API.
@@ -224,14 +222,6 @@
     void moveOpListsToDDL(SkDeferredDisplayList*);
     void copyOpListsFromDDL(const SkDeferredDisplayList*, GrRenderTargetProxy* newDest);
 
-    /**
-     * Purge all the unlocked resources from the cache.
-     * This entry point is mainly meant for timing texture uploads
-     * and is not defined in normal builds of Skia.
-     */
-    void purgeAllUnlockedResources_ForTesting();
-
-
     /*
      * Create a new render target context backed by a deferred-style
      * GrRenderTargetProxy. We guarantee that "asTextureProxy" will succeed for
@@ -266,6 +256,19 @@
                                                  const SkSurfaceProps* surfaceProps = nullptr,
                                                  SkBudgeted budgeted = SkBudgeted::kYes);
 
+    GrAuditTrail* getAuditTrail() { return &fContext->fAuditTrail; }
+
+    GrContextOptions::PersistentCache* getPersistentCache() { return fContext->fPersistentCache; }
+
+    /** This is only useful for debug purposes */
+    SkDEBUGCODE(GrSingleOwner* debugSingleOwner() const { return &fContext->fSingleOwner; } )
+
+#ifdef SK_ENABLE_DUMP_GPU
+    /** Returns a string with detailed information about the context & GPU, in JSON format. */
+    SkString dump() const;
+#endif
+
+#if GR_TEST_UTILS
     /** Reset GPU stats */
     void resetGpuStats() const ;
 
@@ -279,24 +282,24 @@
     void dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) const;
     void printGpuStats() const;
 
-    /** Returns a string with detailed information about the context & GPU, in JSON format. */
-    SkString dump() const;
-
     /** Specify the TextBlob cache limit. If the current cache exceeds this limit it will purge.
         this is for testing only */
-    void setTextBlobCacheLimit_ForTesting(size_t bytes);
+    void testingOnly_setTextBlobCacheLimit(size_t bytes);
 
     /** Get pointer to atlas texture for given mask format. Note that this wraps an
         actively mutating texture in an SkImage. This could yield unexpected results
         if it gets cached or used more generally. */
-    sk_sp<SkImage> getFontAtlasImage_ForTesting(GrMaskFormat format, unsigned int index = 0);
+    sk_sp<SkImage> testingOnly_getFontAtlasImage(GrMaskFormat format, unsigned int index = 0);
 
-    GrAuditTrail* getAuditTrail() { return &fContext->fAuditTrail; }
+    /**
+     * Purge all the unlocked resources from the cache.
+     * This entry point is mainly meant for timing texture uploads
+     * and is not defined in normal builds of Skia.
+     */
+    void testingOnly_purgeAllUnlockedResources();
 
-    GrContextOptions::PersistentCache* getPersistentCache() { return fContext->fPersistentCache; }
-
-    /** This is only useful for debug purposes */
-    SkDEBUGCODE(GrSingleOwner* debugSingleOwner() const { return &fContext->fSingleOwner; } )
+    void testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject*);
+#endif
 
 private:
     explicit GrContextPriv(GrContext* context) : fContext(context) {}
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 985131e..3b4c73f 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -488,6 +488,15 @@
     fOnFlushCBObjects.push_back(onFlushCBObject);
 }
 
+#if GR_TEST_UTILS
+void GrDrawingManager::testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject* cb) {
+    int n = std::find(fOnFlushCBObjects.begin(), fOnFlushCBObjects.end(), cb) -
+            fOnFlushCBObjects.begin();
+    SkASSERT(n < fOnFlushCBObjects.count());
+    fOnFlushCBObjects.removeShuffle(n);
+}
+#endif
+
 void GrDrawingManager::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
     SkDEBUGCODE(this->validate());
 
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index 66b2259..7b17917 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -77,7 +77,10 @@
                                                       GrBackendSemaphore backendSemaphores[]);
 
     void addOnFlushCallbackObject(GrOnFlushCallbackObject*);
+
+#if GR_TEST_UTILS
     void testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject*);
+#endif
 
     void moveOpListsToDDL(SkDeferredDisplayList* ddl);
     void copyOpListsFromDDL(const SkDeferredDisplayList*, GrRenderTargetProxy* newDest);
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index f21e389..cfb22e8 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -425,4 +425,26 @@
     return this->createTestingOnlyBackendTexture(pixels, w, h, grCT, isRenderTarget, isMipped,
                                                  rowBytes);
 }
+
+#if GR_GPU_STATS
+void GrGpu::Stats::dump(SkString* out) {
+    out->appendf("Render Target Binds: %d\n", fRenderTargetBinds);
+    out->appendf("Shader Compilations: %d\n", fShaderCompilations);
+    out->appendf("Textures Created: %d\n", fTextureCreates);
+    out->appendf("Texture Uploads: %d\n", fTextureUploads);
+    out->appendf("Transfers to Texture: %d\n", fTransfersToTexture);
+    out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates);
+    out->appendf("Number of draws: %d\n", fNumDraws);
+}
+
+void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) {
+    keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds);
+    keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations);
+    keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads);
+    keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws);
+    keys->push_back(SkString("number_of_failed_draws")); values->push_back(fNumFailedDraws);
+}
+
+#endif
+
 #endif
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index ed9be12..917e887 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -317,8 +317,10 @@
         void incNumDraws() { fNumDraws++; }
         void incNumFailedDraws() { ++fNumFailedDraws; }
         void incNumFinishFlushes() { ++fNumFinishFlushes; }
+#if GR_TEST_UTILS
         void dump(SkString*);
         void dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values);
+#endif
         int numDraws() const { return fNumDraws; }
         int numFailedDraws() const { return fNumFailedDraws; }
         int numFinishFlushes() const { return fNumFinishFlushes; }
@@ -333,8 +335,11 @@
         int fNumFailedDraws;
         int fNumFinishFlushes;
 #else
+
+#if GR_TEST_UTILS
         void dump(SkString*) {}
         void dumpKeyValuePairs(SkTArray<SkString>*, SkTArray<double>*) {}
+#endif
         void incRenderTargetBinds() {}
         void incShaderCompilations() {}
         void incTextureCreates() {}
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index c7e08a8..9b17d92 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -717,6 +717,56 @@
     }
 }
 
+#if GR_CACHE_STATS
+void GrResourceCache::getStats(Stats* stats) const {
+    stats->reset();
+
+    stats->fTotal = this->getResourceCount();
+    stats->fNumNonPurgeable = fNonpurgeableResources.count();
+    stats->fNumPurgeable = fPurgeableQueue.count();
+
+    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
+        stats->update(fNonpurgeableResources[i]);
+    }
+    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
+        stats->update(fPurgeableQueue.at(i));
+    }
+}
+
+#if GR_TEST_UTILS
+void GrResourceCache::dumpStats(SkString* out) const {
+    this->validate();
+
+    Stats stats;
+
+    this->getStats(&stats);
+
+    float countUtilization = (100.f * fBudgetedCount) / fMaxCount;
+    float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
+
+    out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes);
+    out->appendf("\t\tEntry Count: current %d"
+                 " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), high %d\n",
+                 stats.fTotal, fBudgetedCount, stats.fWrapped, stats.fNumNonPurgeable,
+                 stats.fScratch, countUtilization, fHighWaterCount);
+    out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
+                 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization,
+                 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes));
+}
+
+void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys,
+                                             SkTArray<double>* values) const {
+    this->validate();
+
+    Stats stats;
+    this->getStats(&stats);
+
+    keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable);
+}
+#endif
+
+#endif
+
 #ifdef SK_DEBUG
 void GrResourceCache::validate() const {
     // Reduce the frequency of validations for large resource counts.
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index 59141ad..c948864 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -233,11 +233,14 @@
 
     void getStats(Stats*) const;
 
+#if GR_TEST_UTILS
     void dumpStats(SkString*) const;
 
     void dumpStatsKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* value) const;
 #endif
 
+#endif
+
 #ifdef SK_DEBUG
     int countUniqueKeysWithTag(const char* tag) const;
 #endif