Add GrSurfaceFillContext

This is a new base class for GrSurfaceDrawContext. It allows any
alpha-type but is restricted to non-blending fills of irects using FPs,
clears,and discards.

Bug: skia:11019

Reviewed-on: https://skia-review.googlesource.com/c/skia/+/341680
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Change-Id: I696df3617719fcd8303faa73fb44b32b3fb4f71c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/344896
diff --git a/gm/clear_swizzle.cpp b/gm/clear_swizzle.cpp
index 268a53a4..aeec946 100644
--- a/gm/clear_swizzle.cpp
+++ b/gm/clear_swizzle.cpp
@@ -23,10 +23,11 @@
     auto make_offscreen = [&](const SkISize dimensions) {
         GrSwizzle readSwizzle  = GrSwizzle::Concat(rtCtx->readSwizzle(), GrSwizzle{"bgra"});
         GrSwizzle writeSwizzle = GrSwizzle::Concat(rtCtx->readSwizzle(), GrSwizzle{"bgra"});
-        return GrSurfaceDrawContext::Make(ctx,
+        return GrSurfaceFillContext::Make(ctx,
+                                          kPremul_SkAlphaType,
                                           rtCtx->colorInfo().refColorSpace(),
-                                          SkBackingFit::kExact,
                                           dimensions,
+                                          SkBackingFit::kExact,
                                           rtCtx->asSurfaceProxy()->backendFormat(),
                                           /* sample count*/ 1,
                                           GrMipmapped::kNo,
@@ -34,8 +35,7 @@
                                           readSwizzle,
                                           writeSwizzle,
                                           kTopLeft_GrSurfaceOrigin,
-                                          SkBudgeted::kYes,
-                                          /* surface props */ nullptr);
+                                          SkBudgeted::kYes);
     };
 
     struct {
diff --git a/gm/samplelocations.cpp b/gm/samplelocations.cpp
index 9ff6454..11e2b7a 100644
--- a/gm/samplelocations.cpp
+++ b/gm/samplelocations.cpp
@@ -358,7 +358,7 @@
             0xffff>()
     );
 
-    offscreenRTC->clear({0,1,0,1});
+    offscreenRTC->clear(SkPMColor4f{0, 1, 0, 1});
 
     // Stencil.
     offscreenRTC->addDrawOp(SampleLocationsTestOp::Make(ctx, canvas->getTotalMatrix(), fGradType));
diff --git a/gn/gpu.gni b/gn/gpu.gni
index d8f87a6..fcda974 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -224,6 +224,8 @@
   "$_src/gpu/GrSurfaceContext.h",
   "$_src/gpu/GrSurfaceDrawContext.cpp",
   "$_src/gpu/GrSurfaceDrawContext.h",
+  "$_src/gpu/GrSurfaceFillContext.cpp",
+  "$_src/gpu/GrSurfaceFillContext.h",
   "$_src/gpu/GrSurfaceProxy.cpp",
   "$_src/gpu/GrSurfaceProxy.h",
   "$_src/gpu/GrSurfaceProxyPriv.h",
diff --git a/include/core/SkRect.h b/include/core/SkRect.h
index 1ecd385..794688b 100644
--- a/include/core/SkRect.h
+++ b/include/core/SkRect.h
@@ -63,6 +63,18 @@
         return SkIRect{0, 0, size.fWidth, size.fHeight};
     }
 
+    /** Returns constructed SkIRect set to (pt.x(), pt.y(), pt.x() + size.width(),
+        pt.y() + size.height()). Does not validate input; size.width() or size.height() may be
+        negative.
+
+        @param pt    values for SkIRect fLeft and fTop
+        @param size  values for SkIRect width and height
+        @return      bounds at pt with width and height of size
+    */
+    static constexpr SkIRect SK_WARN_UNUSED_RESULT MakePtSize(SkIPoint pt, SkISize size) {
+        return MakeXYWH(pt.x(), pt.y(), size.width(), size.height());
+    }
+
     /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkIRect may
         result in fLeft greater than fRight, or fTop greater than fBottom.
 
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 143fbdb..08da5a0 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -591,28 +591,32 @@
                                                      SkColorType colorType,
                                                      const SkColorSpace* colorSpace,
                                                      GrProtected isProtected) {
-    GrPaint paint;
-    paint.setColorFragmentProcessor(std::move(fp));
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+    GrImageInfo info(SkColorTypeToGrColorType(colorType),
+                     kPremul_SkAlphaType,
+                     sk_ref_sp(colorSpace),
+                     bounds.size());
 
-    auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-            context, SkColorTypeToGrColorType(colorType), sk_ref_sp(colorSpace),
-            SkBackingFit::kApprox, bounds.size(), 1, GrMipmapped::kNo, isProtected,
-            kBottomLeft_GrSurfaceOrigin);
-    if (!surfaceDrawContext) {
+    auto surfaceFillContext = GrSurfaceFillContext::Make(context,
+                                                         info,
+                                                         SkBackingFit::kApprox,
+                                                         1,
+                                                         GrMipmapped::kNo,
+                                                         isProtected,
+                                                         kBottomLeft_GrSurfaceOrigin);
+    if (!surfaceFillContext) {
         return nullptr;
     }
 
     SkIRect dstIRect = SkIRect::MakeWH(bounds.width(), bounds.height());
     SkRect srcRect = SkRect::Make(bounds);
-    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
-    surfaceDrawContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
-                                       dstRect, srcRect);
+    surfaceFillContext->fillRectToRectWithFP(srcRect, dstIRect, std::move(fp));
 
-    return SkSpecialImage::MakeDeferredFromGpu(
-            context, dstIRect, kNeedNewImageUniqueID_SpecialImage,
-            surfaceDrawContext->readSurfaceView(), surfaceDrawContext->colorInfo().colorType(),
-            surfaceDrawContext->colorInfo().refColorSpace());
+    return SkSpecialImage::MakeDeferredFromGpu(context,
+                                               dstIRect,
+                                               kNeedNewImageUniqueID_SpecialImage,
+                                               surfaceFillContext->readSurfaceView(),
+                                               surfaceFillContext->colorInfo().colorType(),
+                                               surfaceFillContext->colorInfo().refColorSpace());
 }
 
 sk_sp<SkSpecialImage> SkImageFilter_Base::ImageToColorSpace(SkSpecialImage* src,
diff --git a/src/effects/imagefilters/SkArithmeticImageFilter.cpp b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
index 0ad8b0c..1a954e6 100644
--- a/src/effects/imagefilters/SkArithmeticImageFilter.cpp
+++ b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
@@ -331,8 +331,7 @@
         isProtected = foregroundView.proxy()->isProtected();
     }
 
-    GrPaint paint;
-    std::unique_ptr<GrFragmentProcessor> bgFP;
+    std::unique_ptr<GrFragmentProcessor> fp;
     const auto& caps = *ctx.getContext()->priv().caps();
     GrSamplerState sampler(GrSamplerState::WrapMode::kClampToBorder,
                            GrSamplerState::Filter::kNearest);
@@ -342,13 +341,19 @@
         SkMatrix backgroundMatrix = SkMatrix::Translate(
                 SkIntToScalar(bgSubset.left() - backgroundOffset.fX),
                 SkIntToScalar(bgSubset.top()  - backgroundOffset.fY));
-        bgFP = GrTextureEffect::MakeSubset(std::move(backgroundView), background->alphaType(),
-                                           backgroundMatrix, sampler, bgSubset, caps);
-        bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP),
-                                             background->getColorSpace(), background->alphaType(),
-                                             ctx.colorSpace(), kPremul_SkAlphaType);
+        fp = GrTextureEffect::MakeSubset(std::move(backgroundView),
+                                         background->alphaType(),
+                                         backgroundMatrix,
+                                         sampler,
+                                         bgSubset,
+                                         caps);
+        fp = GrColorSpaceXformEffect::Make(std::move(fp),
+                                           background->getColorSpace(),
+                                           background->alphaType(),
+                                           ctx.colorSpace(),
+                                           kPremul_SkAlphaType);
     } else {
-        bgFP = GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT);
+        fp = GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT);
     }
 
     if (foreground) {
@@ -356,37 +361,41 @@
         SkMatrix foregroundMatrix = SkMatrix::Translate(
                 SkIntToScalar(fgSubset.left() - foregroundOffset.fX),
                 SkIntToScalar(fgSubset.top()  - foregroundOffset.fY));
-        auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView), foreground->alphaType(),
-                                                foregroundMatrix, sampler, fgSubset, caps);
+        auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView),
+                                                foreground->alphaType(),
+                                                foregroundMatrix,
+                                                sampler,
+                                                fgSubset,
+                                                caps);
         fgFP = GrColorSpaceXformEffect::Make(std::move(fgFP),
-                                             foreground->getColorSpace(), foreground->alphaType(),
-                                             ctx.colorSpace(), kPremul_SkAlphaType);
-        paint.setColorFragmentProcessor(
-                GrArithmeticProcessor::Make(std::move(fgFP), std::move(bgFP), fInputs));
-    } else {
-        paint.setColorFragmentProcessor(std::move(bgFP));
+                                             foreground->getColorSpace(),
+                                             foreground->alphaType(),
+                                             ctx.colorSpace(),
+                                             kPremul_SkAlphaType);
+        fp = GrArithmeticProcessor::Make(std::move(fgFP), std::move(fp), fInputs);
     }
 
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-    auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-            context, ctx.grColorType(), ctx.refColorSpace(), SkBackingFit::kApprox, bounds.size(),
-            1, GrMipmapped::kNo, isProtected, kBottomLeft_GrSurfaceOrigin);
-    if (!surfaceDrawContext) {
+    GrImageInfo info(ctx.grColorType(), kPremul_SkAlphaType, ctx.refColorSpace(), bounds.size());
+    auto surfaceFillContext = GrSurfaceFillContext::Make(context,
+                                                         info,
+                                                         SkBackingFit::kApprox,
+                                                         1,
+                                                         GrMipmapped::kNo,
+                                                         isProtected,
+                                                         kBottomLeft_GrSurfaceOrigin);
+    if (!surfaceFillContext) {
         return nullptr;
     }
 
-    SkMatrix matrix;
-    matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
-    surfaceDrawContext->drawRect(nullptr, std::move(paint), GrAA::kNo, matrix,
-                                 SkRect::Make(bounds));
+    surfaceFillContext->fillRectToRectWithFP(bounds, SkIRect::MakeSize(bounds.size()),
+                                             std::move(fp));
 
     return SkSpecialImage::MakeDeferredFromGpu(context,
                                                SkIRect::MakeWH(bounds.width(), bounds.height()),
                                                kNeedNewImageUniqueID_SpecialImage,
-                                               surfaceDrawContext->readSurfaceView(),
-                                               surfaceDrawContext->colorInfo().colorType(),
-                                               surfaceDrawContext->colorInfo().refColorSpace());
+                                               surfaceFillContext->readSurfaceView(),
+                                               surfaceFillContext->colorInfo().colorType(),
+                                               surfaceFillContext->colorInfo().refColorSpace());
 }
 #endif
 
diff --git a/src/effects/imagefilters/SkDisplacementMapEffect.cpp b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
index 81ffb15..64057da 100644
--- a/src/effects/imagefilters/SkDisplacementMapEffect.cpp
+++ b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
@@ -340,32 +340,33 @@
         fp = GrColorSpaceXformEffect::Make(std::move(fp),
                                            color->getColorSpace(), color->alphaType(),
                                            ctx.colorSpace(), kPremul_SkAlphaType);
-
-        GrPaint paint;
-        paint.setColorFragmentProcessor(std::move(fp));
-        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-        SkMatrix matrix;
-        matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y()));
-
-        auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-                context, ctx.grColorType(), ctx.refColorSpace(), SkBackingFit::kApprox,
-                bounds.size(), 1, GrMipmapped::kNo, isProtected, kBottomLeft_GrSurfaceOrigin);
-        if (!surfaceDrawContext) {
+        GrImageInfo info(ctx.grColorType(),
+                         kPremul_SkAlphaType,
+                         ctx.refColorSpace(),
+                         bounds.size());
+        auto surfaceFillContext = GrSurfaceFillContext::Make(context,
+                                                             info,
+                                                             SkBackingFit::kApprox,
+                                                             1,
+                                                             GrMipmapped::kNo,
+                                                             isProtected,
+                                                             kBottomLeft_GrSurfaceOrigin);
+        if (!surfaceFillContext) {
             return nullptr;
         }
 
-        surfaceDrawContext->drawRect(nullptr, std::move(paint), GrAA::kNo, matrix,
-                                     SkRect::Make(colorBounds));
+        surfaceFillContext->fillRectToRectWithFP(colorBounds,
+                                                 SkIRect::MakeSize(colorBounds.size()),
+                                                 std::move(fp));
 
         offset->fX = bounds.left();
         offset->fY = bounds.top();
-        return SkSpecialImage::MakeDeferredFromGpu(
-                context,
-                SkIRect::MakeWH(bounds.width(), bounds.height()),
-                kNeedNewImageUniqueID_SpecialImage,
-                surfaceDrawContext->readSurfaceView(),
-                surfaceDrawContext->colorInfo().colorType(),
-                surfaceDrawContext->colorInfo().refColorSpace());
+        return SkSpecialImage::MakeDeferredFromGpu(context,
+                                                   SkIRect::MakeWH(bounds.width(), bounds.height()),
+                                                   kNeedNewImageUniqueID_SpecialImage,
+                                                   surfaceFillContext->readSurfaceView(),
+                                                   surfaceFillContext->colorInfo().colorType(),
+                                                   surfaceFillContext->colorInfo().refColorSpace());
     }
 #endif
 
diff --git a/src/effects/imagefilters/SkLightingImageFilter.cpp b/src/effects/imagefilters/SkLightingImageFilter.cpp
index 42ca4ba..0e04952 100644
--- a/src/effects/imagefilters/SkLightingImageFilter.cpp
+++ b/src/effects/imagefilters/SkLightingImageFilter.cpp
@@ -441,10 +441,10 @@
 
 private:
 #if SK_SUPPORT_GPU
-    void drawRect(GrSurfaceDrawContext*,
+    void drawRect(GrSurfaceFillContext*,
                   GrSurfaceProxyView srcView,
                   const SkMatrix& matrix,
-                  const SkRect& dstRect,
+                  const SkIRect& dstRect,
                   BoundaryMode boundaryMode,
                   const SkIRect* srcBounds,
                   const SkIRect& bounds) const;
@@ -457,21 +457,17 @@
 };
 
 #if SK_SUPPORT_GPU
-void SkLightingImageFilterInternal::drawRect(GrSurfaceDrawContext* surfaceDrawContext,
+void SkLightingImageFilterInternal::drawRect(GrSurfaceFillContext* surfaceFillContext,
                                              GrSurfaceProxyView srcView,
                                              const SkMatrix& matrix,
-                                             const SkRect& dstRect,
+                                             const SkIRect& dstRect,
                                              BoundaryMode boundaryMode,
                                              const SkIRect* srcBounds,
                                              const SkIRect& bounds) const {
-    SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
-    GrPaint paint;
+    SkIRect srcRect = dstRect.makeOffset(bounds.topLeft());
     auto fp = this->makeFragmentProcessor(std::move(srcView), matrix, srcBounds, boundaryMode,
-                                          *surfaceDrawContext->caps());
-    paint.setColorFragmentProcessor(std::move(fp));
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    surfaceDrawContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
-                                       dstRect, srcRect);
+                                          *surfaceFillContext->caps());
+    surfaceFillContext->fillRectToRectWithFP(srcRect, dstRect, std::move(fp));
 }
 
 sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(
@@ -486,55 +482,61 @@
     GrSurfaceProxyView inputView = input->view(context);
     SkASSERT(inputView.asTextureProxy());
 
-    auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-            context, ctx.grColorType(), ctx.refColorSpace(), SkBackingFit::kApprox,
-            offsetBounds.size(), 1, GrMipmapped::kNo, inputView.proxy()->isProtected(),
-            kBottomLeft_GrSurfaceOrigin);
-    if (!surfaceDrawContext) {
+    GrImageInfo info(ctx.grColorType(),
+                     kPremul_SkAlphaType,
+                     ctx.refColorSpace(),
+                     offsetBounds.size());
+    auto surfaceFillContext = GrSurfaceFillContext::Make(context,
+                                                         info,
+                                                         SkBackingFit::kApprox,
+                                                         1,
+                                                         GrMipmapped::kNo,
+                                                         inputView.proxy()->isProtected(),
+                                                         kBottomLeft_GrSurfaceOrigin);
+    if (!surfaceFillContext) {
         return nullptr;
     }
 
-    SkIRect dstIRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height());
-    SkRect dstRect = SkRect::Make(dstIRect);
+    SkIRect dstRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height());
 
     const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
-    SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
-    SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
-    SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
-    SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
-    SkRect interior = dstRect.makeInset(1, 1);
-    SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
-    SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
-    SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
-    SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
+    SkIRect topLeft = SkIRect::MakeXYWH(0, 0, 1, 1);
+    SkIRect top = SkIRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
+    SkIRect topRight = SkIRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
+    SkIRect left = SkIRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
+    SkIRect interior = dstRect.makeInset(1, 1);
+    SkIRect right = SkIRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
+    SkIRect bottomLeft = SkIRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
+    SkIRect bottom = SkIRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
+    SkIRect bottomRight = SkIRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
 
     const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds;
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, topLeft,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, topLeft,
                    kTopLeft_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, top,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, top,
                    kTop_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, topRight,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, topRight,
                    kTopRight_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, left,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, left,
                    kLeft_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, interior,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, interior,
                    kInterior_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, right,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, right,
                    kRight_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, bottomLeft,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, bottomLeft,
                    kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), inputView, matrix, bottom,
+    this->drawRect(surfaceFillContext.get(), inputView, matrix, bottom,
                    kBottom_BoundaryMode, pSrcBounds, offsetBounds);
-    this->drawRect(surfaceDrawContext.get(), std::move(inputView), matrix, bottomRight,
+    this->drawRect(surfaceFillContext.get(), std::move(inputView), matrix, bottomRight,
                    kBottomRight_BoundaryMode, pSrcBounds, offsetBounds);
 
     return SkSpecialImage::MakeDeferredFromGpu(
             context,
             SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()),
             kNeedNewImageUniqueID_SpecialImage,
-            surfaceDrawContext->readSurfaceView(),
-            surfaceDrawContext->colorInfo().colorType(),
-            surfaceDrawContext->colorInfo().refColorSpace());
+            surfaceFillContext->readSurfaceView(),
+            surfaceFillContext->colorInfo().colorType(),
+            surfaceFillContext->colorInfo().refColorSpace());
 }
 #endif
 
diff --git a/src/effects/imagefilters/SkMorphologyImageFilter.cpp b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
index 57e943d..fb4c723 100644
--- a/src/effects/imagefilters/SkMorphologyImageFilter.cpp
+++ b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
@@ -361,7 +361,7 @@
 }
 #endif
 
-static void apply_morphology_rect(GrSurfaceDrawContext* surfaceDrawContext,
+static void apply_morphology_rect(GrSurfaceFillContext* surfaceFillContext,
                                   GrSurfaceProxyView view,
                                   SkAlphaType srcAlphaType,
                                   const SkIRect& srcRect,
@@ -370,17 +370,17 @@
                                   MorphType morphType,
                                   const float range[2],
                                   MorphDirection direction) {
-    GrPaint paint;
-    paint.setColorFragmentProcessor(GrMorphologyEffect::Make(/*inputFP=*/nullptr, std::move(view),
-                                                             srcAlphaType, direction, radius,
-                                                             morphType, range));
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    surfaceDrawContext->fillRectToRect(/*clip=*/nullptr, std::move(paint), GrAA::kNo,
-                                       SkMatrix::I(), SkRect::Make(dstRect),
-                                       SkRect::Make(srcRect));
+    auto fp = GrMorphologyEffect::Make(/*inputFP=*/nullptr,
+                                       std::move(view),
+                                       srcAlphaType,
+                                       direction,
+                                       radius,
+                                       morphType,
+                                       range);
+    surfaceFillContext->fillRectToRectWithFP(srcRect, dstRect, std::move(fp));
 }
 
-static void apply_morphology_rect_no_bounds(GrSurfaceDrawContext* surfaceDrawContext,
+static void apply_morphology_rect_no_bounds(GrSurfaceFillContext* surfaceFillContext,
                                             GrSurfaceProxyView view,
                                             SkAlphaType srcAlphaType,
                                             const SkIRect& srcRect,
@@ -388,16 +388,12 @@
                                             int radius,
                                             MorphType morphType,
                                             MorphDirection direction) {
-    GrPaint paint;
-    paint.setColorFragmentProcessor(GrMorphologyEffect::Make(
-            /*inputFP=*/nullptr, std::move(view), srcAlphaType, direction, radius, morphType));
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    surfaceDrawContext->fillRectToRect(/*clip=*/nullptr, std::move(paint), GrAA::kNo,
-                                       SkMatrix::I(), SkRect::Make(dstRect),
-                                       SkRect::Make(srcRect));
+    auto fp = GrMorphologyEffect::Make(
+            /*inputFP=*/nullptr, std::move(view), srcAlphaType, direction, radius, morphType);
+    surfaceFillContext->fillRectToRectWithFP(srcRect, dstRect, std::move(fp));
 }
 
-static void apply_morphology_pass(GrSurfaceDrawContext* surfaceDrawContext,
+static void apply_morphology_pass(GrSurfaceFillContext* surfaceFillContext,
                                   GrSurfaceProxyView view,
                                   SkAlphaType srcAlphaType,
                                   const SkIRect& srcRect,
@@ -430,15 +426,15 @@
     }
     if (middleSrcRect.width() <= 0) {
         // radius covers srcRect; use bounds over entire draw
-        apply_morphology_rect(surfaceDrawContext, std::move(view), srcAlphaType, srcRect,
+        apply_morphology_rect(surfaceFillContext, std::move(view), srcAlphaType, srcRect,
                               dstRect, radius, morphType, bounds, direction);
     } else {
         // Draw upper and lower margins with bounds; middle without.
-        apply_morphology_rect(surfaceDrawContext, view, srcAlphaType, lowerSrcRect,
+        apply_morphology_rect(surfaceFillContext, view, srcAlphaType, lowerSrcRect,
                               lowerDstRect, radius, morphType, bounds, direction);
-        apply_morphology_rect(surfaceDrawContext, view, srcAlphaType, upperSrcRect,
+        apply_morphology_rect(surfaceFillContext, view, srcAlphaType, upperSrcRect,
                               upperDstRect, radius, morphType, bounds, direction);
-        apply_morphology_rect_no_bounds(surfaceDrawContext, std::move(view), srcAlphaType,
+        apply_morphology_rect_no_bounds(surfaceFillContext, std::move(view), srcAlphaType,
                                         middleSrcRect, middleDstRect, radius, morphType, direction);
     }
 }
@@ -461,37 +457,47 @@
     SkASSERT(radius.width() > 0 || radius.height() > 0);
 
     if (radius.fWidth > 0) {
-        auto dstRTContext = GrSurfaceDrawContext::Make(
-                context, colorType, colorSpace, SkBackingFit::kApprox, rect.size(), 1,
-                GrMipmapped::kNo, proxy->isProtected(), kBottomLeft_GrSurfaceOrigin);
-        if (!dstRTContext) {
+        GrImageInfo info(colorType, kPremul_SkAlphaType, colorSpace, rect.size());
+        auto dstFillContext = GrSurfaceFillContext::Make(context,
+                                                         info,
+                                                         SkBackingFit::kApprox,
+                                                         1,
+                                                         GrMipmapped::kNo,
+                                                         proxy->isProtected(),
+                                                         kBottomLeft_GrSurfaceOrigin);
+        if (!dstFillContext) {
             return nullptr;
         }
 
-        apply_morphology_pass(dstRTContext.get(), std::move(srcView), srcAlphaType,
+        apply_morphology_pass(dstFillContext.get(), std::move(srcView), srcAlphaType,
                               srcRect, dstRect, radius.fWidth, morphType, MorphDirection::kX);
         SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
                                               dstRect.width(), radius.fHeight);
         SkPMColor4f clearColor = MorphType::kErode == morphType
                 ? SK_PMColor4fWHITE : SK_PMColor4fTRANSPARENT;
-        dstRTContext->clear(clearRect, clearColor);
+        dstFillContext->clear(clearRect, clearColor);
 
-        srcView = dstRTContext->readSurfaceView();
-        srcAlphaType = dstRTContext->colorInfo().alphaType();
+        srcView = dstFillContext->readSurfaceView();
+        srcAlphaType = dstFillContext->colorInfo().alphaType();
         srcRect = dstRect;
     }
     if (radius.fHeight > 0) {
-        auto dstRTContext = GrSurfaceDrawContext::Make(
-                context, colorType, colorSpace, SkBackingFit::kApprox, rect.size(), 1,
-                GrMipmapped::kNo, srcView.proxy()->isProtected(), kBottomLeft_GrSurfaceOrigin);
-        if (!dstRTContext) {
+        GrImageInfo info(colorType, kPremul_SkAlphaType, colorSpace, rect.size());
+        auto dstFillContext = GrSurfaceFillContext::Make(context,
+                                                         info,
+                                                         SkBackingFit::kApprox,
+                                                         1,
+                                                         GrMipmapped::kNo,
+                                                         srcView.proxy()->isProtected(),
+                                                         kBottomLeft_GrSurfaceOrigin);
+        if (!dstFillContext) {
             return nullptr;
         }
 
-        apply_morphology_pass(dstRTContext.get(), std::move(srcView), srcAlphaType,
+        apply_morphology_pass(dstFillContext.get(), std::move(srcView), srcAlphaType,
                               srcRect, dstRect, radius.fHeight, morphType, MorphDirection::kY);
 
-        srcView = dstRTContext->readSurfaceView();
+        srcView = dstFillContext->readSurfaceView();
     }
 
     return SkSpecialImage::MakeDeferredFromGpu(context,
diff --git a/src/effects/imagefilters/SkXfermodeImageFilter.cpp b/src/effects/imagefilters/SkXfermodeImageFilter.cpp
index e2d8c45..2ce8f21 100644
--- a/src/effects/imagefilters/SkXfermodeImageFilter.cpp
+++ b/src/effects/imagefilters/SkXfermodeImageFilter.cpp
@@ -251,7 +251,6 @@
         foregroundView = foreground->view(context);
     }
 
-    GrPaint paint;
     std::unique_ptr<GrFragmentProcessor> fp;
     const auto& caps = *ctx.getContext()->priv().caps();
     GrSamplerState sampler(GrSamplerState::WrapMode::kClampToBorder,
@@ -284,26 +283,22 @@
         fp = GrBlendFragmentProcessor::Make(std::move(fgFP), std::move(fp), fMode);
     }
 
-    paint.setColorFragmentProcessor(std::move(fp));
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-    auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-            context, ctx.grColorType(), ctx.refColorSpace(), SkBackingFit::kApprox, bounds.size());
-    if (!surfaceDrawContext) {
+    GrImageInfo info(ctx.grColorType(), kPremul_SkAlphaType, ctx.refColorSpace(), bounds.size());
+    auto surfaceFillContext = GrSurfaceFillContext::Make(context, info, SkBackingFit::kApprox);
+    if (!surfaceFillContext) {
         return nullptr;
     }
 
-    SkMatrix matrix;
-    matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
-    surfaceDrawContext->drawRect(nullptr, std::move(paint), GrAA::kNo, matrix,
-                                 SkRect::Make(bounds));
+    surfaceFillContext->fillRectToRectWithFP(bounds,
+                                             SkIRect::MakeSize(bounds.size()),
+                                             std::move(fp));
 
     return SkSpecialImage::MakeDeferredFromGpu(context,
                                                SkIRect::MakeWH(bounds.width(), bounds.height()),
                                                kNeedNewImageUniqueID_SpecialImage,
-                                               surfaceDrawContext->readSurfaceView(),
-                                               surfaceDrawContext->colorInfo().colorType(),
-                                               surfaceDrawContext->colorInfo().refColorSpace());
+                                               surfaceFillContext->readSurfaceView(),
+                                               surfaceFillContext->colorInfo().colorType(),
+                                               surfaceFillContext->colorInfo().refColorSpace());
 }
 
 #endif
diff --git a/src/gpu/GrOpsTask.h b/src/gpu/GrOpsTask.h
index 9a9dbf7..c0448f4 100644
--- a/src/gpu/GrOpsTask.h
+++ b/src/gpu/GrOpsTask.h
@@ -76,6 +76,19 @@
 
     void discard();
 
+    enum class CanDiscardPreviousOps : bool {
+        kYes = true,
+        kNo = false
+    };
+
+    // Perform book-keeping for a fullscreen clear, regardless of how the clear is implemented later
+    // (i.e. setColorLoadOp(), adding a ClearOp, or adding a GrFillRectOp that covers the device).
+    // Returns true if the clear can be converted into a load op (barring device caps).
+    bool resetForFullscreenClear(CanDiscardPreviousOps);
+
+    // Must only be called if native color buffer clearing is enabled.
+    void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
+
 #ifdef SK_DEBUG
     int numClips() const override { return fNumClips; }
     void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const override;
@@ -124,19 +137,6 @@
     // get preserved across its split tasks.
     void setMustPreserveStencil() { fMustPreserveStencil = true; }
 
-    // Must only be called if native color buffer clearing is enabled.
-    void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
-
-    enum class CanDiscardPreviousOps : bool {
-        kYes = true,
-        kNo = false
-    };
-
-    // Perform book-keeping for a fullscreen clear, regardless of how the clear is implemented later
-    // (i.e. setColorLoadOp(), adding a ClearOp, or adding a GrFillRectOp that covers the device).
-    // Returns true if the clear can be converted into a load op (barring device caps).
-    bool resetForFullscreenClear(CanDiscardPreviousOps);
-
     class OpChain {
     public:
         OpChain(GrOp::Owner, GrProcessorSet::Analysis, GrAppliedClip*, const DstProxyView*);
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index d1a57ce..8ec7265 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -246,7 +246,7 @@
     if (proxy->asRenderTargetProxy()) {
         GrBackendFormat expectedFormat;
         std::tie(ct, expectedFormat) =
-                GrSurfaceDrawContext::GetFallbackColorTypeAndFormat(fImageContext, ct, sampleCnt);
+                GrSurfaceFillContext::GetFallbackColorTypeAndFormat(fImageContext, ct, sampleCnt);
         SkASSERT(expectedFormat == proxy->backendFormat());
     }
     GrSwizzle swizzle = fImageContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), ct);
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index ab40c07..b9c9444 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -45,8 +45,6 @@
 
     std::unique_ptr<GrSurfaceContext> surfaceContext;
     if (proxy->asRenderTargetProxy()) {
-        SkASSERT(info.alphaType() == kPremul_SkAlphaType ||
-                 info.alphaType() == kOpaque_SkAlphaType);
         // Will we ever want a swizzle that is not the default write swizzle for the format and
         // colorType here? If so we will need to manually pass that in.
         GrSwizzle writeSwizzle;
@@ -55,12 +53,19 @@
                                                                    info.colorType());
         }
         GrSurfaceProxyView writeView(readView.refProxy(), readView.origin(), writeSwizzle);
-        surfaceContext = std::make_unique<GrSurfaceDrawContext>(context,
-                                                                std::move(readView),
-                                                                std::move(writeView),
-                                                                info.colorType(),
-                                                                info.refColorSpace(),
-                                                                /*surface props*/ nullptr);
+        if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
+            surfaceContext = std::make_unique<GrSurfaceDrawContext>(context,
+                                                                    std::move(readView),
+                                                                    std::move(writeView),
+                                                                    info.colorType(),
+                                                                    info.refColorSpace(),
+                                                                    /*surface props*/ nullptr);
+        } else {
+            surfaceContext = std::make_unique<GrSurfaceFillContext>(context,
+                                                                    std::move(readView),
+                                                                    std::move(writeView),
+                                                                    info);
+        }
     } else {
         surfaceContext = std::make_unique<GrSurfaceContext>(context, std::move(readView), info);
     }
@@ -237,11 +242,14 @@
             GrColorType colorType = (canvas2DFastPath || srcIsCompressed)
                                             ? GrColorType::kRGBA_8888
                                             : this->colorInfo().colorType();
-            tempCtx = GrSurfaceDrawContext::Make(
-                    dContext, colorType, this->colorInfo().refColorSpace(), SkBackingFit::kApprox,
-                    dstInfo.dimensions(), 1, GrMipMapped::kNo, GrProtected::kNo,
-                    kTopLeft_GrSurfaceOrigin);
-            if (!tempCtx) {
+            SkAlphaType alphaType = canvas2DFastPath ? dstInfo.alphaType()
+                                                     : this->colorInfo().alphaType();
+            GrImageInfo tempInfo(colorType,
+                                 alphaType,
+                                 this->colorInfo().refColorSpace(),
+                                 dstInfo.dimensions());
+            auto sfc = GrSurfaceFillContext::Make(dContext, tempInfo, SkBackingFit::kApprox);
+            if (!sfc) {
                 return false;
             }
 
@@ -253,25 +261,17 @@
                     fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
                     dstInfo = dstInfo.makeColorType(GrColorType::kRGBA_8888);
                 }
-                // The render target context is incorrectly tagged as kPremul even though we're
-                // writing unpremul data thanks to the PMToUPM effect. Fake out the dst alpha type
-                // so we don't double unpremul.
-                dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
             } else {
                 fp = GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType());
             }
             if (!fp) {
                 return false;
             }
-            GrPaint paint;
-            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-            paint.setColorFragmentProcessor(std::move(fp));
-
-            tempCtx->asRenderTargetContext()->fillRectToRect(
-                    nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
-                    SkRect::MakeWH(dstInfo.width(), dstInfo.height()),
-                    SkRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height()));
+            sfc->fillRectToRectWithFP(SkIRect::MakePtSize(pt, dstInfo.dimensions()),
+                                      SkIRect::MakeSize(dstInfo.dimensions()),
+                                      std::move(fp));
             pt = {0, 0};
+            tempCtx = std::move(sfc);
         } else {
             auto restrictions = this->caps()->getDstCopyRestrictions(this->asRenderTargetProxy(),
                                                                      this->colorInfo().colorType());
@@ -404,7 +404,7 @@
     bool canvas2DFastPath = !caps->avoidWritePixelsFastPath() && premul && !needColorConversion &&
                             (srcInfo.colorType() == GrColorType::kRGBA_8888 ||
                              srcInfo.colorType() == GrColorType::kBGRA_8888) &&
-                            SkToBool(this->asRenderTargetContext()) &&
+                            this->asFillContext() &&
                             (dstColorType == GrColorType::kRGBA_8888 ||
                              dstColorType == GrColorType::kBGRA_8888) &&
                             rgbaDefaultFormat.isValid() &&
@@ -434,7 +434,7 @@
         // we can use a draw instead which doesn't have this origin restriction. Thus for render
         // targets we will use top left and otherwise we will make the origins match.
         GrSurfaceOrigin tempOrigin =
-                this->asRenderTargetContext() ? kTopLeft_GrSurfaceOrigin : this->origin();
+                this->asFillContext() ? kTopLeft_GrSurfaceOrigin : this->origin();
         auto tempProxy = dContext->priv().proxyProvider()->createProxy(
                 format, srcInfo.dimensions(), GrRenderable::kNo, 1, GrMipmapped::kNo,
                 SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
@@ -455,7 +455,7 @@
             return false;
         }
 
-        if (this->asRenderTargetContext()) {
+        if (this->asFillContext()) {
             std::unique_ptr<GrFragmentProcessor> fp;
             if (canvas2DFastPath) {
                 fp = dContext->priv().createUPMToPMEffect(
@@ -470,13 +470,10 @@
             if (!fp) {
                 return false;
             }
-            GrPaint paint;
-            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-            paint.setColorFragmentProcessor(std::move(fp));
-            this->asRenderTargetContext()->fillRectToRect(
-                    nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
-                    SkRect::MakeXYWH(pt.fX, pt.fY, srcInfo.width(), srcInfo.height()),
-                    SkRect::MakeWH(srcInfo.width(), srcInfo.height()));
+            this->asFillContext()->fillRectToRectWithFP(
+                    SkIRect::MakeSize(srcInfo.dimensions()),
+                    SkIRect::MakePtSize(pt, srcInfo.dimensions()),
+                    std::move(fp));
         } else {
             SkIRect srcRect = SkIRect::MakeWH(srcInfo.width(), srcInfo.height());
             SkIPoint dstPoint = SkIPoint::Make(pt.fX, pt.fY);
diff --git a/src/gpu/GrSurfaceContext.h b/src/gpu/GrSurfaceContext.h
index 9e1b3c6..60fc978 100644
--- a/src/gpu/GrSurfaceContext.h
+++ b/src/gpu/GrSurfaceContext.h
@@ -23,10 +23,11 @@
 class GrAuditTrail;
 class GrDrawingManager;
 class GrRecordingContext;
-class GrSurfaceDrawContext;
 class GrRenderTargetProxy;
 class GrSingleOwner;
 class GrSurface;
+class GrSurfaceDrawContext;
+class GrSurfaceFillContext;
 class GrSurfaceProxy;
 class GrTextureProxy;
 struct SkIPoint;
@@ -43,7 +44,8 @@
                                                   GrSurfaceProxyView readView,
                                                   const GrColorInfo&);
 
-    // Makes either a GrSurfaceContext or a GrSurfaceDrawContext, depending on GrRenderable.
+    // Makes either a GrSurfaceContext, GrFillDrawContext, or a GrSurfaceDrawContext, depending on
+    // GrRenderable and the GrImageInfo.
     static std::unique_ptr<GrSurfaceContext> Make(GrRecordingContext*,
                                                   const GrImageInfo&,
                                                   const GrBackendFormat&,
@@ -55,6 +57,7 @@
                                                   GrProtected = GrProtected::kNo,
                                                   SkBudgeted = SkBudgeted::kYes);
 
+    // Same as the above but chooses the texture format using the default format for the color type.
     static std::unique_ptr<GrSurfaceContext> Make(GrRecordingContext*,
                                                   const GrImageInfo&,
                                                   SkBackingFit = SkBackingFit::kExact,
@@ -159,6 +162,7 @@
     }
 
     virtual GrSurfaceDrawContext* asRenderTargetContext() { return nullptr; }
+    virtual GrSurfaceFillContext* asFillContext() { return nullptr; }
 
     /**
      * Rescales the contents of srcRect. The gamma in which the rescaling occurs is controlled by
diff --git a/src/gpu/GrSurfaceDrawContext.cpp b/src/gpu/GrSurfaceDrawContext.cpp
index efe7671..3721f2a 100644
--- a/src/gpu/GrSurfaceDrawContext.cpp
+++ b/src/gpu/GrSurfaceDrawContext.cpp
@@ -73,7 +73,6 @@
 #define ASSERT_SINGLE_OWNER        GR_ASSERT_SINGLE_OWNER(this->singleOwner())
 #define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
 #define RETURN_FALSE_IF_ABANDONED  if (fContext->abandoned()) { return false; }
-#define RETURN_NULL_IF_ABANDONED   if (fContext->abandoned()) { return nullptr; }
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -202,43 +201,6 @@
                                       surfaceProps);
 }
 
-static inline GrColorType color_type_fallback(GrColorType ct) {
-    switch (ct) {
-        // kRGBA_8888 is our default fallback for many color types that may not have renderable
-        // backend formats.
-        case GrColorType::kAlpha_8:
-        case GrColorType::kBGR_565:
-        case GrColorType::kABGR_4444:
-        case GrColorType::kBGRA_8888:
-        case GrColorType::kRGBA_1010102:
-        case GrColorType::kBGRA_1010102:
-        case GrColorType::kRGBA_F16:
-        case GrColorType::kRGBA_F16_Clamped:
-            return GrColorType::kRGBA_8888;
-        case GrColorType::kAlpha_F16:
-            return GrColorType::kRGBA_F16;
-        case GrColorType::kGray_8:
-            return GrColorType::kRGB_888x;
-        default:
-            return GrColorType::kUnknown;
-    }
-}
-
-std::tuple<GrColorType, GrBackendFormat> GrSurfaceDrawContext::GetFallbackColorTypeAndFormat(
-        GrImageContext* context, GrColorType colorType, int sampleCnt) {
-    auto caps = context->priv().caps();
-    do {
-        auto format = caps->getDefaultBackendFormat(colorType, GrRenderable::kYes);
-        // We continue to the fallback color type if there no default renderable format or we
-        // requested msaa and the format doesn't support msaa.
-        if (format.isValid() && caps->isFormatRenderable(format, sampleCnt)) {
-            return {colorType, format};
-        }
-        colorType = color_type_fallback(colorType);
-    } while (colorType != GrColorType::kUnknown);
-    return {GrColorType::kUnknown, {}};
-}
-
 std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeWithFallback(
         GrRecordingContext* context,
         GrColorType colorType,
@@ -326,28 +288,16 @@
                                            sk_sp<SkColorSpace> colorSpace,
                                            const SkSurfaceProps* surfaceProps,
                                            bool flushTimeOpsTask)
-        : GrSurfaceContext(context,
-                           std::move(readView),
-                           {colorType, kPremul_SkAlphaType, std::move(colorSpace)})
-        , fWriteView(std::move(writeView))
+        : GrSurfaceFillContext(context,
+                               std::move(readView),
+                               std::move(writeView),
+                               {colorType, kPremul_SkAlphaType, std::move(colorSpace)},
+                               flushTimeOpsTask)
         , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
-        , fFlushTimeOpsTask(flushTimeOpsTask)
         , fGlyphPainter(*this) {
-    fOpsTask = sk_ref_sp(context->priv().drawingManager()->getLastOpsTask(this->asSurfaceProxy()));
-    SkASSERT(this->asSurfaceProxy() == fWriteView.proxy());
-    SkASSERT(this->origin() == fWriteView.origin());
-
     SkDEBUGCODE(this->validate();)
 }
 
-#ifdef SK_DEBUG
-void GrSurfaceDrawContext::onValidate() const {
-    if (fOpsTask && !fOpsTask->isClosed()) {
-        SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get());
-    }
-}
-#endif
-
 GrSurfaceDrawContext::~GrSurfaceDrawContext() {
     ASSERT_SINGLE_OWNER
 }
@@ -371,27 +321,6 @@
     return GrMipmapped::kNo;
 }
 
-GrOpsTask* GrSurfaceDrawContext::getOpsTask() {
-    ASSERT_SINGLE_OWNER
-    SkDEBUGCODE(this->validate();)
-
-    if (!fOpsTask || fOpsTask->isClosed()) {
-        sk_sp<GrOpsTask> newOpsTask = this->drawingManager()->newOpsTask(this->writeSurfaceView(),
-                                                                         fFlushTimeOpsTask);
-        if (fOpsTask && fNumStencilSamples > 0) {
-            // Store the stencil values in memory upon completion of fOpsTask.
-            fOpsTask->setMustPreserveStencil();
-            // Reload the stencil buffer content at the beginning of newOpsTask.
-            // FIXME: Could the topo sort insert a task between these two that modifies the stencil
-            // values?
-            newOpsTask->setInitialStencilContent(GrOpsTask::StencilContent::kPreserved);
-        }
-        fOpsTask = std::move(newOpsTask);
-    }
-    SkASSERT(!fOpsTask->isClosed());
-    return fOpsTask.get();
-}
-
 static SkColor compute_canonical_color(const SkPaint& paint, bool lcd) {
     SkColor canonicalColor = SkPaintPriv::ComputeLuminanceColor(paint);
     if (lcd) {
@@ -516,99 +445,6 @@
     }
 }
 
-void GrSurfaceDrawContext::discard() {
-    ASSERT_SINGLE_OWNER
-    RETURN_IF_ABANDONED
-    SkDEBUGCODE(this->validate();)
-    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "discard", fContext);
-
-    AutoCheckFlush acf(this->drawingManager());
-
-    this->getOpsTask()->discard();
-}
-
-static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
-    paint->setColor4f(color);
-    if (color.isOpaque()) {
-        // Can just rely on the src-over blend mode to do the right thing
-        paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
-    } else {
-        // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
-        // were src blended
-        paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
-    }
-}
-
-// NOTE: We currently pass the premul color unmodified to the gpu, since we assume the GrRTC has a
-// premul alpha type. If we ever support different alpha type render targets, this function should
-// transform the color as appropriate.
-void GrSurfaceDrawContext::internalClear(const SkIRect* scissor,
-                                         const SkPMColor4f& color,
-                                         bool upgradePartialToFull) {
-    ASSERT_SINGLE_OWNER
-    RETURN_IF_ABANDONED
-    SkDEBUGCODE(this->validate();)
-    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "clear", fContext);
-
-    // There are three ways clears are handled: load ops, native clears, and draws. Load ops are
-    // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend
-    // supports then. Drawing an axis-aligned rect is the fallback path.
-    GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
-    if (scissor && !scissorState.set(*scissor)) {
-        // The clear is offscreen, so skip it (normally this would be handled by addDrawOp,
-        // except clear ops are not draw ops).
-        return;
-    }
-
-    // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable
-    // the test. We only do this when the clear would be handled by a load op or natively.
-    if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) {
-        if (upgradePartialToFull && (this->caps()->preferFullscreenClears() ||
-                                     this->caps()->shouldInitializeTextures())) {
-            // TODO: wrt the shouldInitializeTextures path, it would be more performant to
-            // only clear the entire target if we knew it had not been cleared before. As
-            // is this could end up doing a lot of redundant clears.
-            scissorState.setDisabled();
-        } else {
-            // Unlike with stencil clears, we also allow clears up to the logical dimensions of the
-            // render target to overflow into any approx-fit padding of the backing store dimensions
-            scissorState.relaxTest(this->dimensions());
-        }
-    }
-
-    if (!scissorState.enabled()) {
-        // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also
-        // discard all prior ops in the current task since the color buffer will be overwritten.
-        GrOpsTask* opsTask = this->getOpsTask();
-        if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
-            !this->caps()->performColorClearsAsDraws()) {
-            SkPMColor4f clearColor = this->writeSurfaceView().swizzle().applyTo(color);
-            // The op list was emptied and native clears are allowed, so just use the load op
-            opsTask->setColorLoadOp(GrLoadOp::kClear, clearColor.array());
-            return;
-        } else {
-            // Will use an op for the clear, reset the load op to discard since the op will
-            // blow away the color buffer contents
-            opsTask->setColorLoadOp(GrLoadOp::kDiscard);
-        }
-    }
-
-    // At this point we are either a partial clear or a fullscreen clear that couldn't be applied
-    // as a load op.
-    bool clearAsDraw = this->caps()->performColorClearsAsDraws() ||
-                       (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
-    if (clearAsDraw) {
-        GrPaint paint;
-        clear_to_grpaint(color, &paint);
-        this->addDrawOp(nullptr,
-                        GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
-                                                    SkRect::Make(scissorState.rect())));
-    } else {
-        SkPMColor4f clearColor = this->writeSurfaceView().swizzle().applyTo(color);
-        this->addOp(GrClearOp::MakeColor(fContext, scissorState, clearColor.array()));
-    }
-}
-
 void GrSurfaceDrawContext::drawPaint(const GrClip* clip,
                                      GrPaint&& paint,
                                      const SkMatrix& viewMatrix) {
@@ -759,7 +595,7 @@
             // Since the cropped quad became a rectangle which covered the bounds of the rrect,
             // we can draw the rrect directly and ignore the edge flags
             GrPaint paint;
-            clear_to_grpaint(*constColor, &paint);
+            ClearToGrPaint(constColor->array(), &paint);
             this->drawRRect(nullptr, std::move(paint), result.fAA, SkMatrix::I(), result.fRRect,
                             GrStyle::SimpleFill());
             return QuadOptimization::kSubmitted;
@@ -926,8 +762,8 @@
     int numRequiredSamples = this->numSamples();
     if (useMixedSamplesIfNotMSAA && 1 == numRequiredSamples) {
         SkASSERT(this->asRenderTargetProxy()->canUseMixedSamples(*this->caps()));
-        numRequiredSamples = this->caps()->internalMultisampleCount(
-                this->asSurfaceProxy()->backendFormat());
+        numRequiredSamples =
+                this->caps()->internalMultisampleCount(this->asSurfaceProxy()->backendFormat());
     }
     SkASSERT(numRequiredSamples > 0);
 
@@ -1990,12 +1826,6 @@
     }
 }
 
-void GrSurfaceDrawContext::addOp(GrOp::Owner op) {
-    GrDrawingManager* drawingMgr = this->drawingManager();
-    this->getOpsTask()->addOp(drawingMgr,
-            std::move(op), GrTextureResolveManager(drawingMgr), *this->caps());
-}
-
 void GrSurfaceDrawContext::addDrawOp(const GrClip* clip,
                                      GrOp::Owner op,
                                      const std::function<WillAddOpFn>& willAddFn) {
@@ -2023,9 +1853,12 @@
     bool skipDraw = false;
     if (clip) {
         // Have a complex clip, so defer to its early clip culling
-        GrAAType aaType = usesHWAA ? GrAAType::kMSAA :
-                                (op->hasAABloat() ? GrAAType::kCoverage :
-                                                    GrAAType::kNone);
+        GrAAType aaType;
+        if (usesHWAA) {
+            aaType = GrAAType::kMSAA;
+        } else {
+            aaType = op->hasAABloat() ? GrAAType::kCoverage : GrAAType::kNone;
+        }
         skipDraw = clip->apply(fContext, this, aaType, usesUserStencilBits,
                                &appliedClip, &bounds) == GrClip::Effect::kClippedOut;
     } else {
@@ -2131,31 +1964,3 @@
     dstProxyView->setDstSampleType(fDstSampleType);
     return true;
 }
-
-bool GrSurfaceDrawContext::blitTexture(GrSurfaceProxyView view,
-                                       const SkIRect& srcRect,
-                                       const SkIPoint& dstPoint) {
-    SkASSERT(view.asTextureProxy());
-    SkIRect clippedSrcRect;
-    SkIPoint clippedDstPoint;
-    if (!GrClipSrcRectAndDstPoint(this->asSurfaceProxy()->dimensions(), view.proxy()->dimensions(),
-                                  srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) {
-        return false;
-    }
-
-    GrPaint paint;
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-    auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
-    if (!fp) {
-        return false;
-    }
-    paint.setColorFragmentProcessor(std::move(fp));
-
-    this->fillRectToRect(
-            nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
-            SkRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(),
-                             clippedSrcRect.height()),
-            SkRect::Make(clippedSrcRect));
-    return true;
-}
diff --git a/src/gpu/GrSurfaceDrawContext.h b/src/gpu/GrSurfaceDrawContext.h
index 36498dc..6d85a09 100644
--- a/src/gpu/GrSurfaceDrawContext.h
+++ b/src/gpu/GrSurfaceDrawContext.h
@@ -18,14 +18,12 @@
 #include "src/gpu/GrOpsTask.h"
 #include "src/gpu/GrPaint.h"
 #include "src/gpu/GrRenderTargetProxy.h"
-#include "src/gpu/GrSurfaceContext.h"
+#include "src/gpu/GrSurfaceFillContext.h"
 #include "src/gpu/GrSurfaceProxyView.h"
 #include "src/gpu/GrXferProcessor.h"
 #include "src/gpu/geometry/GrQuad.h"
 #include "src/gpu/text/GrTextBlob.h"
 
-#include <tuple>
-
 class GrBackendSemaphore;
 class GrClip;
 class GrColorSpaceXform;
@@ -58,7 +56,7 @@
 /**
  * A helper object to orchestrate commands (draws, etc...) for GrSurfaces that are GrRenderTargets.
  */
-class GrSurfaceDrawContext : public GrSurfaceContext {
+class GrSurfaceDrawContext : public GrSurfaceFillContext {
 public:
     static std::unique_ptr<GrSurfaceDrawContext> Make(GrRecordingContext*,
                                                       GrColorType,
@@ -99,10 +97,6 @@
                                                       SkBudgeted,
                                                       const SkSurfaceProps*);
 
-    static std::tuple<GrColorType, GrBackendFormat> GetFallbackColorTypeAndFormat(GrImageContext*,
-                                                                                  GrColorType,
-                                                                                  int sampleCnt);
-
     // Same as previous factory but will try to use fallback GrColorTypes if the one passed in
     // fails. The fallback GrColorType will have at least the number of channels and precision per
     // channel as the passed in GrColorType. It may also swizzle the changes (e.g., BGRA -> RGBA).
@@ -154,25 +148,6 @@
     ~GrSurfaceDrawContext() override;
 
     /**
-     * Provides a perfomance hint that the render target's contents are allowed
-     * to become undefined.
-     */
-    void discard();
-
-    /**
-     * Clear the rect of the render target to the given color.
-     * @param rect  the rect to clear to
-     * @param color the color to clear to.
-     */
-    void clear(const SkIRect& rect, const SkPMColor4f& color) {
-        this->internalClear(&rect, color);
-    }
-    // Clears the entire render target to the color.
-    void clear(const SkPMColor4f& color) {
-        this->internalClear(nullptr, color);
-    }
-
-    /**
      *  Draw everywhere (respecting the clip) with the paint.
      */
     void drawPaint(const GrClip*, GrPaint&&, const SkMatrix& viewMatrix);
@@ -559,20 +534,11 @@
                           const SkGlyphRunList& glyphRunList);
 
     /**
-     * Draws the src texture with no matrix. The dstRect is the dstPoint with the width and height
-     * of the srcRect. The srcRect and dstRect are clipped to the bounds of the src and dst surfaces
-     * respectively.
-     */
-    bool blitTexture(GrSurfaceProxyView view, const SkIRect& srcRect, const SkIPoint& dstPoint);
-
-    /**
      * Adds the necessary signal and wait semaphores and adds the passed in SkDrawable to the
      * command stream.
      */
     void drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>, const SkRect& bounds);
 
-    GrOpsTask* getOpsTask();
-
     // called to note the last clip drawn to the stencil buffer.
     // TODO: remove after clipping overhaul.
     void setLastClip(uint32_t clipStackGenID,
@@ -595,12 +561,6 @@
                opsTask->fLastClipNumAnalyticElements != numClipAnalyticElements;
     }
 
-    // Clear at minimum the pixels within 'scissor', but is allowed to clear the full render target
-    // if that is the more performant option.
-    void clearAtLeast(const SkIRect& scissor, const SkPMColor4f& color) {
-        this->internalClear(&scissor, color, /* upgrade to full */ true);
-    }
-
     void clearStencilClip(const SkIRect& scissor, bool insideStencilMask) {
         this->internalStencilClear(&scissor, insideStencilMask);
     }
@@ -652,8 +612,6 @@
      */
     GrSurfaceProxy::UniqueID uniqueID() const { return this->asSurfaceProxy()->uniqueID(); }
 
-    void addOp(GrOp::Owner);
-
     // Allows caller of addDrawOp to know which op list an op will be added to.
     using WillAddOpFn = void(GrOp*, uint32_t opsTaskID);
     // These perform processing specific to GrDrawOp-derived ops before recording them into an
@@ -681,10 +639,6 @@
     bool wrapsVkSecondaryCB() const { return this->asRenderTargetProxy()->wrapsVkSecondaryCB(); }
     GrMipmapped mipmapped() const;
 
-    // TODO: See if it makes sense for this to return a const& instead and require the callers to
-    // make a copy (which refs the proxy) if needed.
-    GrSurfaceProxyView writeSurfaceView() { return fWriteView; }
-
     // This entry point should only be called if the backing GPU object is known to be
     // instantiated.
     GrRenderTarget* accessRenderTarget() { return this->asSurfaceProxy()->peekRenderTarget(); }
@@ -693,7 +647,6 @@
 
 #if GR_TEST_UTILS
     void testingOnly_SetPreserveOpsOnFullClear() { fPreserveOpsOnFullClear_TestingOnly = true; }
-    GrOpsTask* testingOnly_PeekLastOpsTask() { return fOpsTask.get(); }
 #endif
 
 private:
@@ -701,13 +654,9 @@
 
     GrAAType chooseAAType(GrAA);
 
-    SkDEBUGCODE(void onValidate() const override;)
-
-    GrOpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const;
+    GrOpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const override;
     void setNeedsStencil(bool useMixedSamplesIfNotMSAA);
 
-    void internalClear(const SkIRect* scissor, const SkPMColor4f&,
-                       bool upgradePartialToFull = false);
     void internalStencilClear(const SkIRect* scissor, bool insideStencilMask);
 
     // Only consumes the GrPaint if successful.
@@ -772,14 +721,7 @@
 
     SkGlyphRunListPainter* glyphPainter() { return &fGlyphPainter; }
 
-    GrSurfaceProxyView fWriteView;
-
-    // In MDB-mode the GrOpsTask can be closed by some other surfaceDrawContext that has picked
-    // it up. For this reason, the GrOpsTask should only ever be accessed via 'getOpsTask'.
-    sk_sp<GrOpsTask> fOpsTask;
-
     SkSurfaceProps fSurfaceProps;
-    bool fFlushTimeOpsTask;
 
     int fNumStencilSamples = 0;
 
@@ -789,7 +731,7 @@
     bool fPreserveOpsOnFullClear_TestingOnly = false;
 #endif
     SkGlyphRunListPainter fGlyphPainter;
-    using INHERITED = GrSurfaceContext;
+    using INHERITED = GrSurfaceFillContext;
 };
 
 #endif
diff --git a/src/gpu/GrSurfaceFillContext.cpp b/src/gpu/GrSurfaceFillContext.cpp
new file mode 100644
index 0000000..49bf84d
--- /dev/null
+++ b/src/gpu/GrSurfaceFillContext.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/GrSurfaceFillContext.h"
+
+#include "include/private/GrImageContext.h"
+#include "src/gpu/GrImageContextPriv.h"
+#include "src/gpu/GrProxyProvider.h"
+#include "src/gpu/GrSurfaceDrawContext.h"
+#include "src/gpu/ops/GrClearOp.h"
+#include "src/gpu/ops/GrFillRectOp.h"
+
+#define ASSERT_SINGLE_OWNER        GR_ASSERT_SINGLE_OWNER(this->singleOwner())
+#define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
+
+class AutoCheckFlush {
+public:
+    AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
+        SkASSERT(fDrawingManager);
+    }
+    ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
+
+private:
+    GrDrawingManager* fDrawingManager;
+};
+
+static inline GrColorType color_type_fallback(GrColorType ct) {
+    switch (ct) {
+        // kRGBA_8888 is our default fallback for many color types that may not have renderable
+        // backend formats.
+        case GrColorType::kAlpha_8:
+        case GrColorType::kBGR_565:
+        case GrColorType::kABGR_4444:
+        case GrColorType::kBGRA_8888:
+        case GrColorType::kRGBA_1010102:
+        case GrColorType::kBGRA_1010102:
+        case GrColorType::kRGBA_F16:
+        case GrColorType::kRGBA_F16_Clamped:
+            return GrColorType::kRGBA_8888;
+        case GrColorType::kAlpha_F16:
+            return GrColorType::kRGBA_F16;
+        case GrColorType::kGray_8:
+            return GrColorType::kRGB_888x;
+        default:
+            return GrColorType::kUnknown;
+    }
+}
+
+std::tuple<GrColorType, GrBackendFormat> GrSurfaceFillContext::GetFallbackColorTypeAndFormat(
+        GrImageContext* context, GrColorType colorType, int sampleCnt) {
+    auto caps = context->priv().caps();
+    do {
+        auto format = caps->getDefaultBackendFormat(colorType, GrRenderable::kYes);
+        // We continue to the fallback color type if there no default renderable format or we
+        // requested msaa and the format doesn't support msaa.
+        if (format.isValid() && caps->isFormatRenderable(format, sampleCnt)) {
+            return {colorType, format};
+        }
+        colorType = color_type_fallback(colorType);
+    } while (colorType != GrColorType::kUnknown);
+    return {GrColorType::kUnknown, {}};
+}
+
+std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::Make(GrRecordingContext* context,
+                                                                 SkAlphaType alphaType,
+                                                                 sk_sp<SkColorSpace> colorSpace,
+                                                                 SkISize dimensions,
+                                                                 SkBackingFit fit,
+                                                                 const GrBackendFormat& format,
+                                                                 int sampleCount,
+                                                                 GrMipmapped mipmapped,
+                                                                 GrProtected isProtected,
+                                                                 GrSwizzle readSwizzle,
+                                                                 GrSwizzle writeSwizzle,
+                                                                 GrSurfaceOrigin origin,
+                                                                 SkBudgeted budgeted) {
+    SkASSERT(context);
+    SkASSERT(!dimensions.isEmpty());
+    SkASSERT(sampleCount >= 1);
+    SkASSERT(format.isValid() && format.backend() == context->backend());
+    if (alphaType == kPremul_SkAlphaType || alphaType == kOpaque_SkAlphaType) {
+        return GrSurfaceDrawContext::Make(context,
+                                          std::move(colorSpace),
+                                          fit,
+                                          dimensions,
+                                          format,
+                                          sampleCount,
+                                          mipmapped,
+                                          isProtected,
+                                          readSwizzle,
+                                          writeSwizzle,
+                                          origin,
+                                          budgeted,
+                                          /* surface props*/ nullptr);
+    }
+
+    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
+                                                                               dimensions,
+                                                                               GrRenderable::kYes,
+                                                                               sampleCount,
+                                                                               mipmapped,
+                                                                               fit,
+                                                                               budgeted,
+                                                                               isProtected);
+    if (!proxy) {
+        return nullptr;
+    }
+    GrImageInfo info(GrColorType::kUnknown, alphaType, std::move(colorSpace), dimensions);
+    GrSurfaceProxyView readView(            proxy, origin,  readSwizzle);
+    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
+    auto fillContext = std::make_unique<GrSurfaceFillContext>(context,
+                                                              std::move(readView),
+                                                              std::move(writeView),
+                                                              info.colorInfo());
+    fillContext->discard();
+    return fillContext;
+}
+
+std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::Make(GrRecordingContext* context,
+                                                                 GrImageInfo info,
+                                                                 SkBackingFit fit,
+                                                                 int sampleCount,
+                                                                 GrMipmapped mipmapped,
+                                                                 GrProtected isProtected,
+                                                                 GrSurfaceOrigin origin,
+                                                                 SkBudgeted budgeted) {
+    if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
+        return GrSurfaceDrawContext::Make(context,
+                                          info.colorType(),
+                                          info.refColorSpace(),
+                                          fit,
+                                          info.dimensions(),
+                                          sampleCount,
+                                          mipmapped,
+                                          isProtected,
+                                          origin,
+                                          budgeted,
+                                          nullptr);
+    }
+    GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(info.colorType(),
+                                                                             GrRenderable::kYes);
+    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
+                                                                               info.dimensions(),
+                                                                               GrRenderable::kYes,
+                                                                               sampleCount,
+                                                                               mipmapped,
+                                                                               fit,
+                                                                               budgeted,
+                                                                               isProtected);
+    if (!proxy) {
+        return nullptr;
+    }
+    GrSwizzle readSwizzle  = context->priv().caps()->getReadSwizzle (format, info.colorType());
+    GrSwizzle writeSwizzle = context->priv().caps()->getWriteSwizzle(format, info.colorType());
+
+    GrSurfaceProxyView readView(            proxy, origin,  readSwizzle);
+    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
+    auto fillContext = std::make_unique<GrSurfaceFillContext>(context,
+                                                              std::move(readView),
+                                                              std::move(writeView),
+                                                              info.colorInfo());
+    fillContext->discard();
+    return fillContext;
+}
+
+std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::MakeWithFallback(
+        GrRecordingContext* context,
+        GrImageInfo info,
+        SkBackingFit fit,
+        int sampleCount,
+        GrMipmapped mipmapped,
+        GrProtected isProtected,
+        GrSurfaceOrigin origin,
+        SkBudgeted budgeted) {
+    if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
+        return GrSurfaceDrawContext::MakeWithFallback(context,
+                                                      info.colorType(),
+                                                      info.refColorSpace(),
+                                                      fit,
+                                                      info.dimensions(),
+                                                      sampleCount,
+                                                      mipmapped,
+                                                      isProtected,
+                                                      origin,
+                                                      budgeted,
+                                                      nullptr);
+    }
+    auto [ct, _] = GetFallbackColorTypeAndFormat(context, info.colorType(), sampleCount);
+    if (ct == GrColorType::kUnknown) {
+        return nullptr;
+    }
+    info = info.makeColorType(ct);
+    return GrSurfaceFillContext::Make(context,
+                                      info,
+                                      fit,
+                                      sampleCount,
+                                      mipmapped,
+                                      isProtected,
+                                      origin,
+                                      budgeted);
+}
+
+std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::MakeFromBackendTexture(
+        GrRecordingContext* context,
+        GrColorInfo info,
+        const GrBackendTexture& tex,
+        int sampleCount,
+        GrSurfaceOrigin origin,
+        sk_sp<GrRefCntedCallback> releaseHelper) {
+    SkASSERT(sampleCount > 0);
+
+    if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
+        return GrSurfaceDrawContext::MakeFromBackendTexture(context,
+                                                            info.colorType(),
+                                                            info.refColorSpace(),
+                                                            tex,
+                                                            sampleCount,
+                                                            origin,
+                                                            nullptr,
+                                                            std::move(releaseHelper));
+    }
+    const GrBackendFormat& format = tex.getBackendFormat();
+    GrSwizzle readSwizzle, writeSwizzle;
+    if (info.colorType() != GrColorType::kUnknown) {
+        if (!context->priv().caps()->areColorTypeAndFormatCompatible(info.colorType(), format)) {
+            return nullptr;
+        }
+        readSwizzle  = context->priv().caps()->getReadSwizzle (format, info.colorType());
+        writeSwizzle = context->priv().caps()->getWriteSwizzle(format, info.colorType());
+    }
+
+    sk_sp<GrTextureProxy> proxy(context->priv().proxyProvider()->wrapRenderableBackendTexture(
+            tex, sampleCount, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
+            std::move(releaseHelper)));
+    if (!proxy) {
+        return nullptr;
+    }
+
+    GrSurfaceProxyView readView(            proxy, origin,  readSwizzle);
+    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
+
+    return std::make_unique<GrSurfaceFillContext>(context,
+                                                  std::move(readView),
+                                                  std::move(writeView),
+                                                  std::move(info));
+
+}
+
+// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
+// GrOpsTask to be picked up and added to by GrSurfaceFillContext lower in the call
+// stack. When this occurs with a closed GrOpsTask, a new one will be allocated
+// when the GrSurfaceFillContext attempts to use it (via getOpsTask).
+GrSurfaceFillContext::GrSurfaceFillContext(GrRecordingContext* context,
+                                           GrSurfaceProxyView readView,
+                                           GrSurfaceProxyView writeView,
+                                           const GrColorInfo& colorInfo,
+                                           bool flushTimeOpsTask)
+        : GrSurfaceContext(context, std::move(readView), std::move(colorInfo))
+        , fWriteView(std::move(writeView))
+        , fFlushTimeOpsTask(flushTimeOpsTask) {
+    fOpsTask = sk_ref_sp(context->priv().drawingManager()->getLastOpsTask(this->asSurfaceProxy()));
+    SkASSERT(this->asSurfaceProxy() == fWriteView.proxy());
+    SkASSERT(this->origin() == fWriteView.origin());
+
+    SkDEBUGCODE(this->validate();)
+}
+
+void GrSurfaceFillContext::fillRectWithFP(const SkIRect& dstRect,
+                                          std::unique_ptr<GrFragmentProcessor> fp) {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceFillContext", "fillRectWithFP", fContext);
+
+    AutoCheckFlush acf(this->drawingManager());
+
+    GrPaint paint;
+    paint.setColorFragmentProcessor(std::move(fp));
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+    auto op = GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
+                                          SkRect::Make(dstRect));
+    this->addDrawOp(std::move(op));
+}
+
+void GrSurfaceFillContext::addDrawOp(GrOp::Owner owner) {
+    GrDrawOp* op = static_cast<GrDrawOp*>(owner.get());
+    GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
+    auto clip = GrAppliedClip::Disabled();
+    const GrCaps& caps = *this->caps();
+    GrProcessorSet::Analysis analysis = op->finalize(caps,
+                                                     &clip,
+                                                     /*mixed sample coverage*/ false,
+                                                     clampType);
+    SkASSERT(!(op->fixedFunctionFlags() & GrDrawOp::FixedFunctionFlags::kUsesStencil));
+    SkASSERT(!analysis.requiresDstTexture());
+    SkRect bounds = owner->bounds();
+    // We shouldn't have coverage AA or hairline draws in fill contexts.
+    SkASSERT(!op->hasAABloat() && !op->hasZeroArea());
+    if (!bounds.intersect(this->asSurfaceProxy()->getBoundsRect())) {
+        return;
+    }
+    op->setClippedBounds(op->bounds());
+    SkDEBUGCODE(op->fAddDrawOpCalled = true;)
+
+    GrXferProcessor::DstProxyView dstProxyView;
+    this->getOpsTask()->addDrawOp(fContext->priv().drawingManager(),
+                                  std::move(owner),
+                                  analysis,
+                                  std::move(clip),
+                                  dstProxyView,
+                                  GrTextureResolveManager(this->drawingManager()),
+                                  caps);
+}
+
+void GrSurfaceFillContext::ClearToGrPaint(std::array<float, 4> color, GrPaint* paint) {
+    paint->setColor4f({color[0], color[1], color[2], color[3]});
+    if (color[3] == 1.f) {
+        // Can just rely on the src-over blend mode to do the right thing.
+        // This may improve batching.
+        paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
+    } else {
+        // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
+        // were src blended
+        paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
+    }
+}
+
+void GrSurfaceFillContext::addOp(GrOp::Owner op) {
+    GrDrawingManager* drawingMgr = this->drawingManager();
+    this->getOpsTask()->addOp(drawingMgr,
+                              std::move(op),
+                              GrTextureResolveManager(drawingMgr),
+                              *this->caps());
+}
+
+GrOpsTask* GrSurfaceFillContext::getOpsTask() {
+    ASSERT_SINGLE_OWNER
+    SkDEBUGCODE(this->validate();)
+
+    if (!fOpsTask || fOpsTask->isClosed()) {
+        sk_sp<GrOpsTask> newOpsTask = this->drawingManager()->newOpsTask(this->writeSurfaceView(),
+                                                                         fFlushTimeOpsTask);
+        if (fOpsTask) {
+            this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get());
+        }
+        fOpsTask = std::move(newOpsTask);
+    }
+    SkASSERT(!fOpsTask->isClosed());
+    return fOpsTask.get();
+}
+
+#ifdef SK_DEBUG
+void GrSurfaceFillContext::onValidate() const {
+    if (fOpsTask && !fOpsTask->isClosed()) {
+        SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get());
+    }
+}
+#endif
+
+void GrSurfaceFillContext::discard() {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "discard", fContext);
+
+    AutoCheckFlush acf(this->drawingManager());
+
+    this->getOpsTask()->discard();
+}
+
+void GrSurfaceFillContext::internalClear(const SkIRect* scissor,
+                                         std::array<float, 4> color,
+                                         bool upgradePartialToFull) {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "clear", fContext);
+
+    // There are three ways clears are handled: load ops, native clears, and draws. Load ops are
+    // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend
+    // supports then. Drawing an axis-aligned rect is the fallback path.
+    GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
+    if (scissor && !scissorState.set(*scissor)) {
+        // The clear is offscreen, so skip it (normally this would be handled by addDrawOp,
+        // except clear ops are not draw ops).
+        return;
+    }
+
+    // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable
+    // the test. We only do this when the clear would be handled by a load op or natively.
+    if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) {
+        if (upgradePartialToFull && (this->caps()->preferFullscreenClears() ||
+                                     this->caps()->shouldInitializeTextures())) {
+            // TODO: wrt the shouldInitializeTextures path, it would be more performant to
+            // only clear the entire target if we knew it had not been cleared before. As
+            // is this could end up doing a lot of redundant clears.
+            scissorState.setDisabled();
+        } else {
+            // Unlike with stencil clears, we also allow clears up to the logical dimensions of the
+            // render target to overflow into any approx-fit padding of the backing store dimensions
+            scissorState.relaxTest(this->dimensions());
+        }
+    }
+
+    if (!scissorState.enabled()) {
+        // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also
+        // discard all prior ops in the current task since the color buffer will be overwritten.
+        GrOpsTask* opsTask = this->getOpsTask();
+        if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
+            !this->caps()->performColorClearsAsDraws()) {
+            color = this->writeSurfaceView().swizzle().applyTo(color);
+            // The op list was emptied and native clears are allowed, so just use the load op
+            opsTask->setColorLoadOp(GrLoadOp::kClear, color);
+            return;
+        } else {
+            // Will use an op for the clear, reset the load op to discard since the op will
+            // blow away the color buffer contents
+            opsTask->setColorLoadOp(GrLoadOp::kDiscard);
+        }
+    }
+
+    // At this point we are either a partial clear or a fullscreen clear that couldn't be applied
+    // as a load op.
+    bool clearAsDraw = this->caps()->performColorClearsAsDraws() ||
+                       (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
+    if (clearAsDraw) {
+        GrPaint paint;
+        ClearToGrPaint(color, &paint);
+        auto op = GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
+                                              SkRect::Make(scissorState.rect()));
+        this->addDrawOp(std::move(op));
+    } else {
+        color = this->writeSurfaceView().swizzle().applyTo(color);
+        this->addOp(GrClearOp::MakeColor(fContext, scissorState, color));
+    }
+}
+
+bool GrSurfaceFillContext::blitTexture(GrSurfaceProxyView view,
+                                       const SkIRect& srcRect,
+                                       const SkIPoint& dstPoint) {
+    SkASSERT(view.asTextureProxy());
+    SkIRect clippedSrcRect;
+    SkIPoint clippedDstPoint;
+    if (!GrClipSrcRectAndDstPoint(this->dimensions(),
+                                  view.dimensions(),
+                                  srcRect,
+                                  dstPoint,
+                                  &clippedSrcRect,
+                                  &clippedDstPoint)) {
+        return false;
+    }
+
+    auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
+    auto dstRect = SkIRect::MakePtSize(clippedDstPoint, clippedSrcRect.size());
+    auto srcRectF = SkRect::Make(clippedSrcRect);
+    this->fillRectToRectWithFP(srcRectF, dstRect, std::move(fp));
+    return true;
+}
diff --git a/src/gpu/GrSurfaceFillContext.h b/src/gpu/GrSurfaceFillContext.h
new file mode 100644
index 0000000..88f192e
--- /dev/null
+++ b/src/gpu/GrSurfaceFillContext.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrSurfaceFillContext_DEFINED
+#define GrSurfaceFillContext_DEFINED
+
+#include "include/core/SkSize.h"
+#include "include/private/GrTypesPriv.h"
+#include "src/gpu/GrImageInfo.h"
+#include "src/gpu/GrOpsTask.h"
+#include "src/gpu/GrSurfaceContext.h"
+#include "src/gpu/GrSwizzle.h"
+#include "src/gpu/effects/GrMatrixEffect.h"
+
+#include <array>
+#include <tuple>
+
+class GrFragmentProcessor;
+class GrImageContext;
+class GrOp;
+class GrBackendFormat;
+class GrRecordingContext;
+class GrSurfaceProxyView;
+class SkColorSpace;
+
+class GrSurfaceFillContext : public GrSurfaceContext {
+public:
+    /**
+     * Checks whether the passed color type is renderable with the passed context. If so, the
+     * same color type is passed back along with the default format used for the color type. If
+     * not, provides an alternative (perhaps lower bit depth and/or unorm instead of float) color
+     * type that is supported along with it's default format or kUnknown if there no renderable
+     * fallback format.
+     */
+    static std::tuple<GrColorType, GrBackendFormat> GetFallbackColorTypeAndFormat(GrImageContext*,
+                                                                                  GrColorType,
+                                                                                  int sampleCount);
+
+    GrSurfaceFillContext(GrRecordingContext*,
+                         GrSurfaceProxyView readView,
+                         GrSurfaceProxyView writeView,
+                         const GrColorInfo&,
+                         bool flushTimeOpsTask = false);
+
+    /**
+     * Uses GrImageInfo's color type to pick the default texture format. Will return a
+     * GrSurfaceDrawContext if possible.
+     */
+    static std::unique_ptr<GrSurfaceFillContext> Make(GrRecordingContext*,
+                                                      GrImageInfo,
+                                                      SkBackingFit = SkBackingFit::kExact,
+                                                      int sampleCount = 1,
+                                                      GrMipmapped = GrMipmapped::kNo,
+                                                      GrProtected = GrProtected::kNo,
+                                                      GrSurfaceOrigin = kTopLeft_GrSurfaceOrigin,
+                                                      SkBudgeted = SkBudgeted::kYes);
+
+    /**
+     * Like the above but uses GetFallbackColorTypeAndFormat to find a fallback color type (and
+     * compatible format) if the passed GrImageInfo's color type is not renderable.
+     */
+    static std::unique_ptr<GrSurfaceFillContext> MakeWithFallback(
+            GrRecordingContext*,
+            GrImageInfo,
+            SkBackingFit = SkBackingFit::kExact,
+            int sampleCount = 1,
+            GrMipmapped = GrMipmapped::kNo,
+            GrProtected = GrProtected::kNo,
+            GrSurfaceOrigin = kTopLeft_GrSurfaceOrigin,
+            SkBudgeted = SkBudgeted::kYes);
+
+    /**
+     * Makes a custom configured GrSurfaceFillContext where the caller specifies the specific
+     * texture format and swizzles. The color type will be kUnknown. Returns a GrSurfaceDrawContext
+     * if possible.
+     */
+    static std::unique_ptr<GrSurfaceFillContext> Make(GrRecordingContext*,
+                                                      SkAlphaType,
+                                                      sk_sp<SkColorSpace>,
+                                                      SkISize dimensions,
+                                                      SkBackingFit,
+                                                      const GrBackendFormat&,
+                                                      int sampleCount,
+                                                      GrMipmapped,
+                                                      GrProtected,
+                                                      GrSwizzle readSwizzle,
+                                                      GrSwizzle writeSwizzle,
+                                                      GrSurfaceOrigin,
+                                                      SkBudgeted);
+
+    /**
+     * Creates a GrSurfaceFillContext from an existing GrBackendTexture. The GrColorInfo's color
+     * type must be compatible with backend texture's format or this will fail. All formats are
+     * considered compatible with kUnknown. Returns a GrSurfaceDrawContext if possible.
+     */
+    static std::unique_ptr<GrSurfaceFillContext> MakeFromBackendTexture(
+            GrRecordingContext*,
+            GrColorInfo,
+            const GrBackendTexture&,
+            int sampleCount,
+            GrSurfaceOrigin,
+            sk_sp<GrRefCntedCallback> releaseHelper);
+
+    GrSurfaceFillContext* asFillContext() override { return this; }
+
+    /**
+     * Provides a performance hint that the render target's contents are allowed
+     * to become undefined.
+     */
+    void discard();
+
+    /**
+     * Clear the rect of the render target to the given color.
+     * @param rect  the rect to clear to
+     * @param color the color to clear to.
+     */
+    template <SkAlphaType AlphaType>
+    void clear(const SkIRect& rect, const SkRGBA4f<AlphaType>& color) {
+        this->internalClear(&rect, this->adjustColorAlphaType(color));
+    }
+
+    /** Clears the entire render target to the color. */
+    template <SkAlphaType AlphaType> void clear(const SkRGBA4f<AlphaType>& color) {
+        this->internalClear(nullptr, this->adjustColorAlphaType(color));
+    }
+
+    /**
+     * Clear at minimum the pixels within 'scissor', but is allowed to clear the full render target
+     * if that is the more performant option.
+     */
+    template <SkAlphaType AlphaType>
+    void clearAtLeast(const SkIRect& scissor, const SkRGBA4f<AlphaType>& color) {
+        this->internalClear(&scissor,
+                            this->adjustColorAlphaType(color),
+                            /* upgrade to full */ true);
+    }
+
+    /** Fills 'dstRect' with 'fp' */
+    void fillRectWithFP(const SkIRect& dstRect, std::unique_ptr<GrFragmentProcessor> fp);
+
+    /**
+     * A convenience version of fillRectWithFP that applies a coordinate transformation via
+     * GrMatrixEffect.
+     */
+    void fillRectWithFP(const SkIRect& dstRect,
+                        const SkMatrix& localMatrix,
+                        std::unique_ptr<GrFragmentProcessor> fp) {
+        fp = GrMatrixEffect::Make(localMatrix, std::move(fp));
+        this->fillRectWithFP(dstRect, std::move(fp));
+    }
+
+    /** Fills 'dstRect' with 'fp' using a local matrix that maps 'srcRect' to 'dstRect' */
+    void fillRectToRectWithFP(const SkRect& srcRect,
+                              const SkIRect& dstRect,
+                              std::unique_ptr<GrFragmentProcessor> fp) {
+        SkMatrix lm;
+        lm.setRectToRect(SkRect::Make(dstRect), srcRect, SkMatrix::kFill_ScaleToFit);
+        this->fillRectWithFP(dstRect, lm, std::move(fp));
+    }
+
+    /** Fills 'dstRect' with 'fp' using a local matrix that maps 'srcRect' to 'dstRect' */
+    void fillRectToRectWithFP(const SkIRect& srcRect,
+                              const SkIRect& dstRect,
+                              std::unique_ptr<GrFragmentProcessor> fp) {
+        this->fillRectToRectWithFP(SkRect::Make(srcRect), dstRect, std::move(fp));
+    }
+
+    /** Fills the entire render target with the passed FP. */
+    void fillWithFP(std::unique_ptr<GrFragmentProcessor> fp) {
+        this->fillRectWithFP(SkIRect::MakeSize(fWriteView.proxy()->dimensions()), std::move(fp));
+    }
+
+    /**
+     * A convenience version of fillWithFP that applies a coordinate transformation via
+     * GrMatrixEffect and fills the entire render target.
+     */
+    void fillWithFP(const SkMatrix& localMatrix, std::unique_ptr<GrFragmentProcessor> fp) {
+        this->fillRectWithFP(
+                SkIRect::MakeSize(fWriteView.proxy()->dimensions()), localMatrix, std::move(fp));
+    }
+
+    /**
+     * Draws the src texture with no matrix. The dstRect is the dstPoint with the width and height
+     * of the srcRect. The srcRect and dstRect are clipped to the bounds of the src and dst surfaces
+     * respectively.
+     */
+    bool blitTexture(GrSurfaceProxyView view, const SkIRect& srcRect, const SkIPoint& dstPoint);
+
+    GrOpsTask* getOpsTask();
+
+    int numSamples() const { return this->asRenderTargetProxy()->numSamples(); }
+    bool wrapsVkSecondaryCB() const { return this->asRenderTargetProxy()->wrapsVkSecondaryCB(); }
+    GrMipmapped mipmapped() const;
+
+#if GR_TEST_UTILS
+    GrOpsTask* testingOnly_PeekLastOpsTask() { return fOpsTask.get(); }
+#endif
+
+    const GrSurfaceProxyView& writeSurfaceView() const { return fWriteView; }
+
+protected:
+    /**
+     * Creates a constant color paint for a clear, using src-over if possible to improve batching.
+     */
+    static void ClearToGrPaint(std::array<float, 4> color, GrPaint* paint);
+
+    void addOp(GrOp::Owner);
+
+private:
+    template <SkAlphaType AlphaType>
+    static std::array<float, 4> ConvertColor(SkRGBA4f<AlphaType> color);
+
+    template <SkAlphaType AlphaType>
+    std::array<float, 4> adjustColorAlphaType(SkRGBA4f<AlphaType> color) const;
+
+    /** Override to be notified in subclass before the current ops task is replaced. */
+    virtual void willReplaceOpsTask(GrOpsTask* prevTask, GrOpsTask* nextTask) {}
+
+    /**
+     * Override to be called to participate in the decision to discard all previous ops if a
+     * fullscreen clear occurs.
+     */
+    virtual GrOpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const {
+        return GrOpsTask::CanDiscardPreviousOps::kYes;
+    }
+
+    void internalClear(const SkIRect* scissor,
+                       std::array<float, 4> color,
+                       bool upgradePartialToFull = false);
+
+    void addDrawOp(GrOp::Owner);
+
+    SkDEBUGCODE(void onValidate() const override;)
+
+    GrSurfaceProxyView fWriteView;
+
+    // The GrOpsTask can be closed by some other surface context that has picked it up. For this
+    // reason, the GrOpsTask should only ever be accessed via 'getOpsTask'.
+    sk_sp<GrOpsTask> fOpsTask;
+
+    bool fFlushTimeOpsTask;
+
+    using INHERITED = GrSurfaceContext;
+};
+
+template<>
+inline std::array<float, 4> GrSurfaceFillContext::ConvertColor<kPremul_SkAlphaType>(
+        SkPMColor4f color) {
+    return color.unpremul().array();
+}
+
+template<>
+inline std::array<float, 4> GrSurfaceFillContext::ConvertColor<kUnpremul_SkAlphaType>(
+        SkColor4f color) {
+    return color.premul().array();
+}
+
+template <SkAlphaType AlphaType>
+std::array<float, 4> GrSurfaceFillContext::adjustColorAlphaType(SkRGBA4f<AlphaType> color) const {
+    if (AlphaType == kUnknown_SkAlphaType ||
+        this->colorInfo().alphaType() == kUnknown_SkAlphaType) {
+        return color.array();
+    }
+    return (AlphaType == this->colorInfo().alphaType()) ? color.array() : ConvertColor(color);
+}
+
+#endif
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index a588da3..7719dc9 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -291,19 +291,19 @@
         }
     }
     if (src->asTextureProxy()) {
-        auto dstContext = GrSurfaceDrawContext::Make(context,
+        auto dstContext = GrSurfaceFillContext::Make(context,
+                                                     kUnknown_SkAlphaType,
                                                      nullptr,
-                                                     fit,
                                                      {width, height},
+                                                     fit,
                                                      format,
-                                                     /* sample count*/ 1,
+                                                     1,
                                                      mipMapped,
                                                      src->isProtected(),
                                                      GrSwizzle::RGBA(),
                                                      GrSwizzle::RGBA(),
                                                      origin,
-                                                     budgeted,
-                                                     /*surface props*/ nullptr);
+                                                     budgeted);
         GrSurfaceProxyView view(sk_ref_sp(src), origin, GrSwizzle::RGBA());
         if (dstContext && dstContext->blitTexture(std::move(view), srcRect, dstPoint)) {
             return dstContext->asSurfaceProxyRef();
diff --git a/src/gpu/GrSwizzle.h b/src/gpu/GrSwizzle.h
index a250842..dad7597 100644
--- a/src/gpu/GrSwizzle.h
+++ b/src/gpu/GrSwizzle.h
@@ -41,8 +41,14 @@
     }
 
     /** Applies this swizzle to the input color and returns the swizzled color. */
+    constexpr std::array<float, 4> applyTo(std::array<float, 4> color) const;
+
+    /** Convenience version for SkRGBA colors. */
     template <SkAlphaType AlphaType>
-    constexpr SkRGBA4f<AlphaType> applyTo(const SkRGBA4f<AlphaType>& color) const;
+    constexpr SkRGBA4f<AlphaType> applyTo(SkRGBA4f<AlphaType> color) const {
+        std::array<float, 4> result = this->applyTo(color.array());
+        return {result[0], result[1], result[2], result[3]};
+    }
 
     void apply(SkRasterPipeline*) const;
 
@@ -56,8 +62,7 @@
 private:
     explicit constexpr GrSwizzle(uint16_t key) : fKey(key) {}
 
-    template <SkAlphaType AlphaType>
-    static constexpr float ComponentIndexToFloat(const SkRGBA4f<AlphaType>& color, int idx);
+    static constexpr float ComponentIndexToFloat(std::array<float, 4>, int idx);
     static constexpr int CToI(char c);
     static constexpr char IToC(int idx);
 
@@ -75,8 +80,7 @@
     return *this;
 }
 
-template <SkAlphaType AlphaType>
-constexpr SkRGBA4f<AlphaType> GrSwizzle::applyTo(const SkRGBA4f<AlphaType>& color) const {
+constexpr std::array<float, 4> GrSwizzle::applyTo(std::array<float, 4> color) const {
     uint32_t key = fKey;
     // Index of the input color that should be mapped to output r.
     int idx = (key & 15);
@@ -93,8 +97,7 @@
     return { outR, outG, outB, outA };
 }
 
-template <SkAlphaType AlphaType>
-constexpr float GrSwizzle::ComponentIndexToFloat(const SkRGBA4f<AlphaType>& color, int idx) {
+constexpr float GrSwizzle::ComponentIndexToFloat(std::array<float, 4> color, int idx) {
     if (idx <= 3) {
         return color[idx];
     }
diff --git a/src/gpu/GrThreadSafeCache.cpp b/src/gpu/GrThreadSafeCache.cpp
index 61749a5..d76db3e 100644
--- a/src/gpu/GrThreadSafeCache.cpp
+++ b/src/gpu/GrThreadSafeCache.cpp
@@ -326,8 +326,7 @@
 
     constexpr int kSampleCnt = 1;
     auto [newCT, format] =
-            GrSurfaceDrawContext::GetFallbackColorTypeAndFormat(
-            dContext, origCT, kSampleCnt);
+            GrSurfaceFillContext::GetFallbackColorTypeAndFormat(dContext, origCT, kSampleCnt);
 
     if (newCT == GrColorType::kUnknown) {
         return {GrSurfaceProxyView(nullptr), nullptr};
diff --git a/src/gpu/effects/GrConfigConversionEffect.fp b/src/gpu/effects/GrConfigConversionEffect.fp
index a9c8154..09c51ae 100644
--- a/src/gpu/effects/GrConfigConversionEffect.fp
+++ b/src/gpu/effects/GrConfigConversionEffect.fp
@@ -22,7 +22,6 @@
 @cppEnd {
     bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* dContext) {
         static constexpr int kSize = 256;
-        static constexpr GrColorType kColorType = GrColorType::kRGBA_8888;
         SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
         uint32_t* srcData = data.get();
         uint32_t* firstRead = data.get() + kSize * kSize;
@@ -40,28 +39,24 @@
                 color[0] = std::min(x, y);
             }
         }
-        memset(firstRead, 0, kSize * kSize * sizeof(uint32_t));
-        memset(secondRead, 0, kSize * kSize * sizeof(uint32_t));
+        std::fill_n( firstRead, kSize * kSize, 0);
+        std::fill_n(secondRead, kSize * kSize, 0);
 
-        const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
-                                                 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+        const SkImageInfo pmII =
+                SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+        const SkImageInfo upmII = pmII.makeAlphaType(kUnpremul_SkAlphaType);
 
-        auto readRTC = GrSurfaceDrawContext::Make(
-                dContext, kColorType, nullptr, SkBackingFit::kExact, {kSize, kSize});
-        auto tempRTC = GrSurfaceDrawContext::Make(
-                dContext, kColorType, nullptr, SkBackingFit::kExact, {kSize, kSize});
-        if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
+        auto readSFC = GrSurfaceFillContext::Make(dContext, upmII, SkBackingFit::kExact);
+        auto tempSFC = GrSurfaceFillContext::Make(dContext,  pmII, SkBackingFit::kExact);
+        if (!readSFC || !tempSFC) {
             return false;
         }
-        // Adding discard to appease vulkan validation warning about loading uninitialized data on
-        // draw
-        readRTC->discard();
 
         // This function is only ever called if we are in a GrDirectContext since we are
         // calling read pixels here. Thus the pixel data will be uploaded immediately and we don't
         // need to keep the pixel data alive in the proxy. Therefore the ReleaseProc is nullptr.
         SkBitmap bitmap;
-        bitmap.installPixels(ii, srcData, 4 * kSize);
+        bitmap.installPixels(pmII, srcData, 4 * kSize);
         bitmap.setImmutable();
 
         GrBitmapTextureMaker maker(dContext, bitmap, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
@@ -70,50 +65,37 @@
             return false;
         }
 
-        static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
-
         // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
         // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
         // We then verify that two reads produced the same values.
 
-        GrPaint paint1;
-        paint1.setColorFragmentProcessor(GrConfigConversionEffect::Make(
-                GrTextureEffect::Make(std::move(dataView), kPremul_SkAlphaType),
-                PMConversion::kToUnpremul));
-        paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-        readRTC->fillRectToRect(nullptr, std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-        if (!readRTC->readPixels(dContext, ii, firstRead, 0, {0, 0})) {
+        auto fp1 = GrConfigConversionEffect::Make(GrTextureEffect::Make(std::move(dataView),
+                                                                        bitmap.alphaType()),
+                                                  PMConversion::kToUnpremul);
+        readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp1));
+        if (!readSFC->readPixels(dContext, upmII, firstRead, 0, {0, 0})) {
             return false;
         }
 
-        // Adding discard to appease vulkan validation warning about loading uninitialized data on
-        // draw
-        tempRTC->discard();
+        auto fp2 = GrConfigConversionEffect::Make(
+                GrTextureEffect::Make(readSFC->readSurfaceView(),
+                                      readSFC->colorInfo().alphaType()),
+                PMConversion::kToPremul);
+        tempSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp2));
 
-        GrPaint paint2;
-        paint2.setColorFragmentProcessor(GrConfigConversionEffect::Make(
-                GrTextureEffect::Make(readRTC->readSurfaceView(), kUnpremul_SkAlphaType),
-                PMConversion::kToPremul));
-        paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
+        auto fp3 = GrConfigConversionEffect::Make(
+                GrTextureEffect::Make(tempSFC->readSurfaceView(),
+                                      tempSFC->colorInfo().alphaType()),
+                PMConversion::kToUnpremul);
+        readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp3));
 
-        tempRTC->fillRectToRect(nullptr, std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-
-        GrPaint paint3;
-        paint3.setColorFragmentProcessor(GrConfigConversionEffect::Make(
-                GrTextureEffect::Make(tempRTC->readSurfaceView(), kPremul_SkAlphaType),
-                PMConversion::kToUnpremul));
-        paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-        readRTC->fillRectToRect(nullptr, std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-
-        if (!readRTC->readPixels(dContext, ii, secondRead, 0, {0, 0})) {
+        if (!readSFC->readPixels(dContext, upmII, secondRead, 0, {0, 0})) {
             return false;
         }
 
         for (int y = 0; y < kSize; ++y) {
             for (int x = 0; x <= y; ++x) {
-                if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
+                if (firstRead[kSize*y + x] != secondRead[kSize*y + x]) {
                     return false;
                 }
             }
diff --git a/src/gpu/effects/generated/GrConfigConversionEffect.cpp b/src/gpu/effects/generated/GrConfigConversionEffect.cpp
index 6c4ec43..1f165cc 100644
--- a/src/gpu/effects/generated/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/generated/GrConfigConversionEffect.cpp
@@ -87,7 +87,6 @@
 
 bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* dContext) {
     static constexpr int kSize = 256;
-    static constexpr GrColorType kColorType = GrColorType::kRGBA_8888;
     SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
     uint32_t* srcData = data.get();
     uint32_t* firstRead = data.get() + kSize * kSize;
@@ -105,28 +104,24 @@
             color[0] = std::min(x, y);
         }
     }
-    memset(firstRead, 0, kSize * kSize * sizeof(uint32_t));
-    memset(secondRead, 0, kSize * kSize * sizeof(uint32_t));
+    std::fill_n(firstRead, kSize * kSize, 0);
+    std::fill_n(secondRead, kSize * kSize, 0);
 
-    const SkImageInfo ii =
+    const SkImageInfo pmII =
             SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+    const SkImageInfo upmII = pmII.makeAlphaType(kUnpremul_SkAlphaType);
 
-    auto readRTC = GrSurfaceDrawContext::Make(dContext, kColorType, nullptr, SkBackingFit::kExact,
-                                              {kSize, kSize});
-    auto tempRTC = GrSurfaceDrawContext::Make(dContext, kColorType, nullptr, SkBackingFit::kExact,
-                                              {kSize, kSize});
-    if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
+    auto readSFC = GrSurfaceFillContext::Make(dContext, upmII, SkBackingFit::kExact);
+    auto tempSFC = GrSurfaceFillContext::Make(dContext, pmII, SkBackingFit::kExact);
+    if (!readSFC || !tempSFC) {
         return false;
     }
-    // Adding discard to appease vulkan validation warning about loading uninitialized data on
-    // draw
-    readRTC->discard();
 
     // This function is only ever called if we are in a GrDirectContext since we are
     // calling read pixels here. Thus the pixel data will be uploaded immediately and we don't
     // need to keep the pixel data alive in the proxy. Therefore the ReleaseProc is nullptr.
     SkBitmap bitmap;
-    bitmap.installPixels(ii, srcData, 4 * kSize);
+    bitmap.installPixels(pmII, srcData, 4 * kSize);
     bitmap.setImmutable();
 
     GrBitmapTextureMaker maker(dContext, bitmap, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
@@ -135,44 +130,29 @@
         return false;
     }
 
-    static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
-
     // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
     // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
     // We then verify that two reads produced the same values.
 
-    GrPaint paint1;
-    paint1.setColorFragmentProcessor(GrConfigConversionEffect::Make(
-            GrTextureEffect::Make(std::move(dataView), kPremul_SkAlphaType),
-            PMConversion::kToUnpremul));
-    paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-    readRTC->fillRectToRect(nullptr, std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-    if (!readRTC->readPixels(dContext, ii, firstRead, 0, {0, 0})) {
+    auto fp1 = GrConfigConversionEffect::Make(
+            GrTextureEffect::Make(std::move(dataView), bitmap.alphaType()),
+            PMConversion::kToUnpremul);
+    readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp1));
+    if (!readSFC->readPixels(dContext, upmII, firstRead, 0, {0, 0})) {
         return false;
     }
 
-    // Adding discard to appease vulkan validation warning about loading uninitialized data on
-    // draw
-    tempRTC->discard();
+    auto fp2 = GrConfigConversionEffect::Make(
+            GrTextureEffect::Make(readSFC->readSurfaceView(), readSFC->colorInfo().alphaType()),
+            PMConversion::kToPremul);
+    tempSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp2));
 
-    GrPaint paint2;
-    paint2.setColorFragmentProcessor(GrConfigConversionEffect::Make(
-            GrTextureEffect::Make(readRTC->readSurfaceView(), kUnpremul_SkAlphaType),
-            PMConversion::kToPremul));
-    paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
+    auto fp3 = GrConfigConversionEffect::Make(
+            GrTextureEffect::Make(tempSFC->readSurfaceView(), tempSFC->colorInfo().alphaType()),
+            PMConversion::kToUnpremul);
+    readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp3));
 
-    tempRTC->fillRectToRect(nullptr, std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-
-    GrPaint paint3;
-    paint3.setColorFragmentProcessor(GrConfigConversionEffect::Make(
-            GrTextureEffect::Make(tempRTC->readSurfaceView(), kPremul_SkAlphaType),
-            PMConversion::kToUnpremul));
-    paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
-    readRTC->fillRectToRect(nullptr, std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-
-    if (!readRTC->readPixels(dContext, ii, secondRead, 0, {0, 0})) {
+    if (!readSFC->readPixels(dContext, upmII, secondRead, 0, {0, 0})) {
         return false;
     }
 
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index aefe227..2f6c1e7 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -88,10 +88,11 @@
         return nullptr;
     }
 
-    auto surfaceDrawContext = GrSurfaceDrawContext::MakeWithFallback(
-            direct, SkColorTypeToGrColorType(targetCT), nullptr, SkBackingFit::kExact,
-            this->dimensions());
-    if (!surfaceDrawContext) {
+    auto info = this->imageInfo().makeColorType(targetCT).makeColorSpace(targetCS);
+    auto surfaceFillContext = GrSurfaceFillContext::MakeWithFallback(direct,
+                                                                     std::move(info),
+                                                                     SkBackingFit::kExact);
+    if (!surfaceFillContext) {
         return nullptr;
     }
 
@@ -101,20 +102,12 @@
                                                  targetCS.get(), this->alphaType());
     SkASSERT(colorFP);
 
-    GrPaint paint;
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    paint.setColorFragmentProcessor(std::move(colorFP));
+    surfaceFillContext->fillWithFP(std::move(colorFP));
+    SkASSERT(surfaceFillContext->asTextureProxy());
 
-    surfaceDrawContext->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
-                                 SkRect::MakeIWH(this->width(), this->height()));
-    if (!surfaceDrawContext->asTextureProxy()) {
-        return nullptr;
-    }
-
-    targetCT = GrColorTypeToSkColorType(surfaceDrawContext->colorInfo().colorType());
-    // MDB: this call is okay bc we know 'surfaceDrawContext' was exact
+    targetCT = GrColorTypeToSkColorType(surfaceFillContext->colorInfo().colorType());
     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(direct), kNeedNewImageUniqueID,
-                                   surfaceDrawContext->readSurfaceView(), targetCT,
+                                   surfaceFillContext->readSurfaceView(), targetCT,
                                    this->alphaType(), std::move(targetCS));
 }
 
diff --git a/src/image/SkImage_GpuBase.h b/src/image/SkImage_GpuBase.h
index 63d34f2..f4f763e 100644
--- a/src/image/SkImage_GpuBase.h
+++ b/src/image/SkImage_GpuBase.h
@@ -17,7 +17,7 @@
 class GrColorSpaceXform;
 class GrDirectContext;
 class GrImageContext;
-class GrSurfaceDrawContext;
+class GrSurfaceFillContext;
 class SkColorSpace;
 
 class SkImage_GpuBase : public SkImage_Base {
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index b203827..18be7eb 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -205,19 +205,22 @@
     }
 
     // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
-    auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-            context, GrColorType::kRGBA_8888, this->refColorSpace(), SkBackingFit::kExact,
-            this->dimensions(), 1, GrMipmapped::kNo, GrProtected::kNo);
-    if (!surfaceDrawContext) {
+    GrImageInfo info(GrColorType::kRGBA_8888,
+                     kPremul_SkAlphaType,
+                     this->refColorSpace(),
+                     this->dimensions());
+    auto surfaceFillContext = GrSurfaceFillContext::Make(context,
+                                                         info,
+                                                         SkBackingFit::kExact,
+                                                         /*sample count*/ 1,
+                                                         GrMipmapped::kNo,
+                                                         GrProtected::kNo);
+    if (!surfaceFillContext) {
         return;
     }
 
-    const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
     const GrCaps& caps = *context->priv().caps();
 
-    GrPaint paint;
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
     auto fp = GrYUVtoRGBEffect::Make(fViews,
                                      fYUVAIndices,
                                      fYUVColorSpace,
@@ -230,11 +233,10 @@
                                                        this->alphaType());
         fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(colorSpaceXform));
     }
-    paint.setColorFragmentProcessor(std::move(fp));
 
-    surfaceDrawContext->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
+    surfaceFillContext->fillWithFP(std::move(fp));
 
-    fRGBView = surfaceDrawContext->readSurfaceView();
+    fRGBView = surfaceFillContext->readSurfaceView();
     SkASSERT(fRGBView.swizzle() == GrSwizzle());
     for (auto& v : fViews) {
         v.reset();
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index 3edcbcc..9cca6a3 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -305,17 +305,24 @@
     }
 
     // TODO: investigate preallocating mip maps here
-    GrColorType ct = SkColorTypeToGrColorType(this->colorType());
-    auto surfaceDrawContext = GrSurfaceDrawContext::Make(
-            ctx, ct, nullptr, SkBackingFit::kExact, this->dimensions(), 1, GrMipmapped::kNo,
-            GrProtected::kNo, kTopLeft_GrSurfaceOrigin, budgeted);
-    if (!surfaceDrawContext) {
+    GrImageInfo info(SkColorTypeToGrColorType(this->colorType()),
+                     kPremul_SkAlphaType,
+                     /*color space*/ nullptr,
+                     this->dimensions());
+    auto surfaceFillContext = GrSurfaceFillContext::Make(ctx,
+                                                         info,
+                                                         SkBackingFit::kExact,
+                                                         1,
+                                                         GrMipmapped::kNo,
+                                                         GrProtected::kNo,
+                                                         kTopLeft_GrSurfaceOrigin,
+                                                         budgeted);
+    if (!surfaceFillContext) {
         return {};
     }
 
     SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
     SkAssertResult(yuvaPixmaps.toYUVAIndices(yuvaIndices));
-    GrPaint paint;
     std::unique_ptr<GrFragmentProcessor> yuvToRgbProcessor =
             GrYUVtoRGBEffect::Make(yuvViews,
                                    yuvaIndices,
@@ -340,18 +347,15 @@
             GrColorSpaceXformEffect::Make(std::move(yuvToRgbProcessor),
                                           srcColorSpace, kOpaque_SkAlphaType,
                                           dstColorSpace, kOpaque_SkAlphaType);
-    paint.setColorFragmentProcessor(std::move(colorConversionProcessor));
-
-    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    const SkRect r = SkRect::Make(this->dimensions());
-
     SkMatrix m = SkEncodedOriginToMatrix(yuvaPixmaps.yuvaInfo().origin(),
                                          this->width(),
                                          this->height());
-    surfaceDrawContext->drawRect(nullptr, std::move(paint), GrAA::kNo, m, r);
+    // The returned matrix is a view matrix but we need a local matrix.
+    SkAssertResult(m.invert(&m));
+    surfaceFillContext->fillWithFP(m, std::move(colorConversionProcessor));
 
-    SkASSERT(surfaceDrawContext->asTextureProxy());
-    return surfaceDrawContext->readSurfaceView();
+    SkASSERT(surfaceFillContext->asTextureProxy());
+    return surfaceFillContext->readSurfaceView();
 }
 
 sk_sp<SkCachedData> SkImage_Lazy::getPlanes(
diff --git a/tests/CopySurfaceTest.cpp b/tests/CopySurfaceTest.cpp
index f05dc86..19dadfc 100644
--- a/tests/CopySurfaceTest.cpp
+++ b/tests/CopySurfaceTest.cpp
@@ -115,8 +115,8 @@
                                                                   srcRect,
                                                                   dstPoint);
                                 } else if (dRenderable == GrRenderable::kYes) {
-                                    SkASSERT(dstContext->asRenderTargetContext());
-                                    result = dstContext->asRenderTargetContext()->blitTexture(
+                                    SkASSERT(dstContext->asFillContext());
+                                    result = dstContext->asFillContext()->blitTexture(
                                             std::move(srcView), srcRect, dstPoint);
                                 }
 
diff --git a/tests/EGLImageTest.cpp b/tests/EGLImageTest.cpp
index b7e8c90..8ad24b6 100644
--- a/tests/EGLImageTest.cpp
+++ b/tests/EGLImageTest.cpp
@@ -184,13 +184,11 @@
 
     // Should not be able to wrap as a RT
     {
-        auto temp = GrSurfaceDrawContext::MakeFromBackendTexture(context0,
-                                                                 colorInfo.colorType(),
-                                                                 /*color space*/ nullptr,
+        auto temp = GrSurfaceFillContext::MakeFromBackendTexture(context0,
+                                                                 colorInfo,
                                                                  backendTex,
                                                                  1,
                                                                  origin,
-                                                                 /*surface props*/ nullptr,
                                                                  /*release helper*/ nullptr);
         if (temp) {
             ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture as a RT.");
diff --git a/tests/GrMipMappedTest.cpp b/tests/GrMipMappedTest.cpp
index 96ef0ae..a075907 100644
--- a/tests/GrMipMappedTest.cpp
+++ b/tests/GrMipMappedTest.cpp
@@ -429,7 +429,7 @@
         auto mipmapRTC = GrSurfaceDrawContext::Make(
             dContext.get(), colorType, nullptr, mipmapProxy, kTopLeft_GrSurfaceOrigin, nullptr);
 
-        mipmapRTC->clear({.1f,.2f,.3f,.4f});
+        mipmapRTC->clear(SkPMColor4f{.1f, .2f, .3f, .4f});
         REPORTER_ASSERT(reporter, drawingManager->getLastRenderTask(mipmapProxy.get()));
         // mipmapProxy's last render task should now just be the opsTask containing the clear.
         REPORTER_ASSERT(reporter,
@@ -475,7 +475,7 @@
         REPORTER_ASSERT(reporter, rtc2Task->dependsOn(initialMipmapRegenTask));
 
         // Render something to dirty the mips.
-        mipmapRTC->clear({.1f,.2f,.3f,.4f});
+        mipmapRTC->clear(SkPMColor4f{.1f, .2f, .3f, .4f});
         auto mipmapRTCTask = sk_ref_sp(mipmapRTC->testingOnly_PeekLastOpsTask());
         REPORTER_ASSERT(reporter, mipmapRTCTask);
 
diff --git a/tests/GrThreadSafeCacheTest.cpp b/tests/GrThreadSafeCacheTest.cpp
index 6db901b..16d267e 100644
--- a/tests/GrThreadSafeCacheTest.cpp
+++ b/tests/GrThreadSafeCacheTest.cpp
@@ -645,7 +645,7 @@
     GrPaint paint;
     paint.setColor4f({0.0f, 0.0f, 1.0f, 1.0f});
 
-    rtc->clear({1.0f, 1.0f, 1.0f, 1.0f});
+    rtc->clear(SkPMColor4f{1.0f, 1.0f, 1.0f, 1.0f});
     rtc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
                   { 10, 10, wh-10.0f, wh-10.0f }, &GrStyle::SimpleFill());
 
diff --git a/tests/OnFlushCallbackTest.cpp b/tests/OnFlushCallbackTest.cpp
index 16a493d..dffa40a 100644
--- a/tests/OnFlushCallbackTest.cpp
+++ b/tests/OnFlushCallbackTest.cpp
@@ -471,7 +471,7 @@
             rContext, GrColorType::kRGBA_8888, nullptr,
             SkBackingFit::kApprox, {3 * kDrawnTileSize, kDrawnTileSize});
 
-    rtc->clear({ 1, 0, 0, 1 });
+    rtc->clear(SkPMColor4f{1, 0, 0, 1});
 
     for (int i = 0; i < 3; ++i) {
         SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp
index 5befdc3..f0aa7b4 100644
--- a/tests/ReadPixelsTest.cpp
+++ b/tests/ReadPixelsTest.cpp
@@ -962,14 +962,11 @@
                 if (src.colorType() == kRGB_888x_SkColorType) {
                     return Surface();
                 }
-                std::unique_ptr<GrSurfaceContext> surfContext;
-                // Renderable + unpremul/unknown is not allowed (yet!), skbug.com/11019
-                if (renderable == GrRenderable::kNo        ||
-                    src.alphaType() == kPremul_SkAlphaType ||
-                    src.alphaType() == kOpaque_SkAlphaType) {
-                    surfContext = GrSurfaceContext::Make(direct, src.info(), SkBackingFit::kExact,
-                                                         origin, renderable);
-                }
+                auto surfContext = GrSurfaceContext::Make(direct,
+                                                          src.info(),
+                                                          SkBackingFit::kExact,
+                                                          origin,
+                                                          renderable);
                 if (surfContext) {
                     surfContext->writePixels(direct,
                                              src.info(),
diff --git a/tests/RectangleTextureTest.cpp b/tests/RectangleTextureTest.cpp
index 9d106de..1c49e0f 100644
--- a/tests/RectangleTextureTest.cpp
+++ b/tests/RectangleTextureTest.cpp
@@ -24,17 +24,14 @@
 static void test_basic_draw_as_src(skiatest::Reporter* reporter, GrDirectContext* dContext,
                                    GrSurfaceProxyView rectView, GrColorType colorType,
                                    SkAlphaType alphaType, uint32_t expectedPixelValues[]) {
-    auto rtContext = GrSurfaceDrawContext::Make(
-            dContext, colorType, nullptr, SkBackingFit::kExact, rectView.proxy()->dimensions());
+    auto fillContext = GrSurfaceFillContext::Make(
+            dContext, {colorType, kPremul_SkAlphaType, nullptr, rectView.dimensions()});
     for (auto filter : {GrSamplerState::Filter::kNearest, GrSamplerState::Filter::kLinear}) {
         for (auto mm : {GrSamplerState::MipmapMode::kNone, GrSamplerState::MipmapMode::kLinear}) {
-            rtContext->clear(SkPMColor4f::FromBytes_RGBA(0xDDCCBBAA));
+            fillContext->clear(SkPMColor4f::FromBytes_RGBA(0xDDCCBBAA));
             auto fp = GrTextureEffect::Make(rectView, alphaType, SkMatrix::I(), filter, mm);
-            GrPaint paint;
-            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-            paint.setColorFragmentProcessor(std::move(fp));
-            rtContext->drawPaint(nullptr, std::move(paint), SkMatrix::I());
-            TestReadPixels(reporter, dContext, rtContext.get(), expectedPixelValues,
+            fillContext->fillWithFP(std::move(fp));
+            TestReadPixels(reporter, dContext, fillContext.get(), expectedPixelValues,
                            "RectangleTexture-basic-draw");
         }
     }
@@ -42,13 +39,13 @@
 
 static void test_clear(skiatest::Reporter* reporter, GrDirectContext* dContext,
                        GrSurfaceContext* rectContext) {
-    if (GrSurfaceDrawContext* rtc = rectContext->asRenderTargetContext()) {
+    if (GrSurfaceFillContext* sfc = rectContext->asFillContext()) {
         // Clear the whole thing.
         GrColor color0 = GrColorPackRGBA(0xA, 0xB, 0xC, 0xD);
-        rtc->clear(SkPMColor4f::FromBytes_RGBA(color0));
+        sfc->clear(SkPMColor4f::FromBytes_RGBA(color0));
 
-        int w = rtc->width();
-        int h = rtc->height();
+        int w = sfc->width();
+        int h = sfc->height();
         int pixelCnt = w * h;
         SkAutoTMalloc<uint32_t> expectedPixels(pixelCnt);
 
@@ -59,14 +56,14 @@
         expectedBytes0[1] = GrColorUnpackG(color0);
         expectedBytes0[2] = GrColorUnpackB(color0);
         expectedBytes0[3] = GrColorUnpackA(color0);
-        for (int i = 0; i < rtc->width() * rtc->height(); ++i) {
+        for (int i = 0; i < sfc->width() * sfc->height(); ++i) {
             expectedPixels.get()[i] = expectedColor0;
         }
 
         // Clear the the top to a different color.
         GrColor color1 = GrColorPackRGBA(0x1, 0x2, 0x3, 0x4);
         SkIRect rect = SkIRect::MakeWH(w, h/2);
-        rtc->clear(rect, SkPMColor4f::FromBytes_RGBA(color1));
+        sfc->clear(rect, SkPMColor4f::FromBytes_RGBA(color1));
 
         uint32_t expectedColor1 = 0;
         uint8_t* expectedBytes1 = reinterpret_cast<uint8_t*>(&expectedColor1);
@@ -81,7 +78,7 @@
             }
         }
 
-        TestReadPixels(reporter, dContext, rtc, expectedPixels.get(), "RectangleTexture-clear");
+        TestReadPixels(reporter, dContext, sfc, expectedPixels.get(), "RectangleTexture-clear");
     }
 }