ccpr: Use lazy proxies with GrCCAtlas

Bug: skia:
Change-Id: I576d9303d451352778de0425e3ecbc561331cd09
Reviewed-on: https://skia-review.googlesource.com/135362
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 212aa36..04b8b81 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -192,8 +192,6 @@
         return true;
     }
 
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
-    const auto* caps = context->contextPriv().caps()->shaderCaps();
     int maxWindowRectangles = renderTargetContext->priv().maxWindowRectangles();
     int maxAnalyticFPs = context->contextPriv().caps()->maxClipAnalyticFPs();
     if (GrFSAAType::kNone != renderTargetContext->fsaaType()) {
@@ -208,8 +206,8 @@
     }
     auto* ccpr = context->contextPriv().drawingManager()->getCoverageCountingPathRenderer();
 
-    GrReducedClip reducedClip(*fStack, devBounds, caps, maxWindowRectangles, maxAnalyticFPs,
-                              ccpr ? maxAnalyticFPs : 0);
+    GrReducedClip reducedClip(*fStack, devBounds, context->contextPriv().caps(),
+                              maxWindowRectangles, maxAnalyticFPs, ccpr ? maxAnalyticFPs : 0);
     if (InitialState::kAllOut == reducedClip.initialState() &&
         reducedClip.maskElements().isEmpty()) {
         return false;
@@ -235,8 +233,7 @@
     // can cause a flush or otherwise change which opList our draw is going into.
     uint32_t opListID = renderTargetContext->getOpList()->uniqueID();
     int rtWidth = renderTargetContext->width(), rtHeight = renderTargetContext->height();
-    if (auto clipFPs = reducedClip.finishAndDetachAnalyticFPs(ccpr, proxyProvider, opListID,
-                                                              rtWidth, rtHeight)) {
+    if (auto clipFPs = reducedClip.finishAndDetachAnalyticFPs(ccpr, opListID, rtWidth, rtHeight)) {
         out->addCoverageFP(std::move(clipFPs));
     }
 
diff --git a/src/gpu/GrOnFlushResourceProvider.cpp b/src/gpu/GrOnFlushResourceProvider.cpp
index ff56c33..535f825 100644
--- a/src/gpu/GrOnFlushResourceProvider.cpp
+++ b/src/gpu/GrOnFlushResourceProvider.cpp
@@ -58,6 +58,13 @@
                                                         sk_sp<GrSurfaceProxy> proxy,
                                                         sk_sp<SkColorSpace> colorSpace,
                                                         const SkSurfaceProps* props) {
+    // Since this is at flush time and these won't be allocated for us by the GrResourceAllocator
+    // we have to manually ensure it is allocated here. The proxy had best have been created
+    // with the kNoPendingIO flag!
+    if (!this->instatiateProxy(proxy.get())) {
+        return nullptr;
+    }
+
     sk_sp<GrRenderTargetContext> renderTargetContext(
         fDrawingMgr->makeRenderTargetContext(std::move(proxy),
                                              std::move(colorSpace),
@@ -67,15 +74,6 @@
         return nullptr;
     }
 
-    auto resourceProvider = fDrawingMgr->getContext()->contextPriv().resourceProvider();
-
-    // Since this is at flush time and these won't be allocated for us by the GrResourceAllocator
-    // we have to manually ensure it is allocated here. The proxy had best have been created
-    // with the kNoPendingIO flag!
-    if (!renderTargetContext->asSurfaceProxy()->instantiate(resourceProvider)) {
-        return nullptr;
-    }
-
     renderTargetContext->discard();
 
     return renderTargetContext;
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index a1f14df..5814c76 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -603,15 +603,16 @@
             std::move(callback), lazyType, desc, origin, fit, budgeted, surfaceFlags));
 }
 
-sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback,
-                                                            Renderable renderable,
-                                                            GrSurfaceOrigin origin,
-                                                            GrPixelConfig config) {
+sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback,
+                                                          Renderable renderable,
+                                                          GrSurfaceOrigin origin,
+                                                          GrPixelConfig config,
+                                                          const GrCaps& caps) {
     GrSurfaceDesc desc;
     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNoPendingIO;
     if (Renderable::kYes == renderable) {
         desc.fFlags = kRenderTarget_GrSurfaceFlag;
-        if (fCaps->maxWindowRectangles() > 0) {
+        if (caps.maxWindowRectangles() > 0) {
             surfaceFlags |= GrInternalSurfaceFlags::kWindowRectsSupport;
         }
     }
@@ -620,8 +621,16 @@
     desc.fConfig = config;
     desc.fSampleCnt = 1;
 
-    return this->createLazyProxy(std::move(callback), desc, origin, GrMipMapped::kNo,
-                                 surfaceFlags, SkBackingFit::kApprox, SkBudgeted::kYes);
+    return sk_sp<GrTextureProxy>(
+            (Renderable::kYes == renderable)
+                    ? new GrTextureRenderTargetProxy(std::move(callback),
+                                                     LazyInstantiationType::kSingleUse, desc,
+                                                     origin, GrMipMapped::kNo,
+                                                     SkBackingFit::kApprox, SkBudgeted::kYes,
+                                                     surfaceFlags)
+                    : new GrTextureProxy(std::move(callback), LazyInstantiationType::kSingleUse,
+                                         desc, origin, GrMipMapped::kNo, SkBackingFit::kApprox,
+                                         SkBudgeted::kYes, surfaceFlags));
 }
 
 bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index c466c98..64b9ac4 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -178,20 +178,19 @@
 
     sk_sp<GrTextureProxy> createLazyProxy(LazyInstantiateCallback&&, const GrSurfaceDesc&,
                                           GrSurfaceOrigin, GrMipMapped, SkBackingFit, SkBudgeted);
-
-    /**
-     * Fully lazy proxies have unspecified width and height. Methods that rely on those values
-     * (e.g., width, height, getBoundsRect) should be avoided.
-     */
-    sk_sp<GrTextureProxy> createFullyLazyProxy(LazyInstantiateCallback&&,
-                                               Renderable, GrSurfaceOrigin, GrPixelConfig);
-
     sk_sp<GrRenderTargetProxy> createLazyRenderTargetProxy(LazyInstantiateCallback&&,
                                                            const GrSurfaceDesc&,
                                                            GrSurfaceOrigin origin,
                                                            GrInternalSurfaceFlags, Textureable,
                                                            GrMipMapped, SkBackingFit, SkBudgeted);
 
+    /**
+     * Fully lazy proxies have unspecified width and height. Methods that rely on those values
+     * (e.g., width, height, getBoundsRect) should be avoided.
+     */
+    static sk_sp<GrTextureProxy> MakeFullyLazyProxy(LazyInstantiateCallback&&, Renderable,
+                                                    GrSurfaceOrigin, GrPixelConfig, const GrCaps&);
+
     // 'proxy' is about to be used as a texture src or drawn to. This query can be used to
     // determine if it is going to need a texture domain or a full clear.
     static bool IsFunctionallyExact(GrSurfaceProxy* proxy);
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index e6cd6b3..2377846 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -34,7 +34,7 @@
  * take a rect in case the caller knows a bound on what is to be drawn through this clip.
  */
 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds,
-                             const GrShaderCaps* caps, int maxWindowRectangles, int maxAnalyticFPs,
+                             const GrCaps* caps, int maxWindowRectangles, int maxAnalyticFPs,
                              int maxCCPRClipPaths)
         : fCaps(caps)
         , fMaxWindowRectangles(maxWindowRectangles)
@@ -630,7 +630,8 @@
         return ClipResult::kNotClipped;
     }
 
-    if (auto fp = GrRRectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRRect, *fCaps)) {
+    if (auto fp = GrRRectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRRect,
+                                      *fCaps->shaderCaps())) {
         fAnalyticFPs.push_back(std::move(fp));
         return ClipResult::kClipped;
     }
@@ -956,8 +957,7 @@
 }
 
 std::unique_ptr<GrFragmentProcessor> GrReducedClip::finishAndDetachAnalyticFPs(
-        GrCoverageCountingPathRenderer* ccpr, GrProxyProvider* proxyProvider, uint32_t opListID,
-        int rtWidth, int rtHeight) {
+        GrCoverageCountingPathRenderer* ccpr, uint32_t opListID, int rtWidth, int rtHeight) {
     // Make sure finishAndDetachAnalyticFPs hasn't been called already.
     SkDEBUGCODE(for (const auto& fp : fAnalyticFPs) { SkASSERT(fp); })
 
@@ -966,8 +966,8 @@
         for (const SkPath& ccprClipPath : fCCPRClipPaths) {
             SkASSERT(ccpr);
             SkASSERT(fHasScissor);
-            auto fp = ccpr->makeClipProcessor(proxyProvider, opListID, ccprClipPath, fScissor,
-                                              rtWidth, rtHeight);
+            auto fp = ccpr->makeClipProcessor(opListID, ccprClipPath, fScissor, rtWidth, rtHeight,
+                                              *fCaps);
             fAnalyticFPs.push_back(std::move(fp));
         }
         fCCPRClipPaths.reset();
diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h
index 87ef346..fcdc66c 100644
--- a/src/gpu/GrReducedClip.h
+++ b/src/gpu/GrReducedClip.h
@@ -26,7 +26,7 @@
     using Element = SkClipStack::Element;
     using ElementList = SkTLList<SkClipStack::Element, 16>;
 
-    GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrShaderCaps* caps,
+    GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrCaps* caps,
                   int maxWindowRectangles = 0, int maxAnalyticFPs = 0, int maxCCPRClipPaths = 0);
 
     enum class InitialState : bool {
@@ -97,9 +97,8 @@
      * may cause flushes or otherwise change which opList the actual draw is going into.
      */
     std::unique_ptr<GrFragmentProcessor> finishAndDetachAnalyticFPs(GrCoverageCountingPathRenderer*,
-                                                                    GrProxyProvider*,
-                                                                    uint32_t opListID,
-                                                                    int rtWidth, int rtHeight);
+                                                                    uint32_t opListID, int rtWidth,
+                                                                    int rtHeight);
 
 private:
     void walkStack(const SkClipStack&, const SkRect& queryBounds);
@@ -132,7 +131,7 @@
 
     void makeEmpty();
 
-    const GrShaderCaps* fCaps;
+    const GrCaps* fCaps;
     const int fMaxWindowRectangles;
     const int fMaxAnalyticFPs;
     const int fMaxCCPRClipPaths;
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp
index cbf6993..94a37e8 100644
--- a/src/gpu/ccpr/GrCCAtlas.cpp
+++ b/src/gpu/ccpr/GrCCAtlas.cpp
@@ -9,8 +9,10 @@
 
 #include "GrCaps.h"
 #include "GrOnFlushResourceProvider.h"
+#include "GrProxyProvider.h"
 #include "GrRectanizer_skyline.h"
 #include "GrRenderTargetContext.h"
+#include "GrTexture.h"
 #include "GrTextureProxy.h"
 #include "SkMakeUnique.h"
 #include "SkMathPriv.h"
@@ -44,9 +46,12 @@
     GrRectanizerSkyline fRectanizer;
 };
 
-GrCCAtlas::GrCCAtlas(const Specs& specs)
+GrCCAtlas::GrCCAtlas(GrPixelConfig pixelConfig, const Specs& specs, const GrCaps& caps)
         : fMaxTextureSize(SkTMax(SkTMax(specs.fMinHeight, specs.fMinWidth),
                                  specs.fMaxPreferredTextureSize)) {
+    // Caller should have cropped any paths to the destination render target instead of asking for
+    // an atlas larger than maxRenderTargetSize.
+    SkASSERT(fMaxTextureSize <= caps.maxTextureSize());
     SkASSERT(specs.fMaxPreferredTextureSize > 0);
 
     // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
@@ -66,14 +71,28 @@
     }
 
     fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
+
+    fTextureProxy = GrProxyProvider::MakeFullyLazyProxy(
+            [this, pixelConfig](GrResourceProvider* resourceProvider) {
+                    if (!resourceProvider) {
+                        return sk_sp<GrTexture>();
+                    }
+                    GrSurfaceDesc desc;
+                    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+                    desc.fWidth = fWidth;
+                    desc.fHeight = fHeight;
+                    desc.fConfig = pixelConfig;
+                    return resourceProvider->createTexture(desc, SkBudgeted::kYes);
+            },
+            GrProxyProvider::Renderable::kYes, kTextureOrigin, pixelConfig, caps);
 }
 
 GrCCAtlas::~GrCCAtlas() {
 }
 
 bool GrCCAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) {
-    // This can't be called anymore once makeClearedTextureProxy() has been called.
-    SkASSERT(!fTextureProxy);
+    // This can't be called anymore once makeRenderTargetContext() has been called.
+    SkASSERT(!fTextureProxy->priv().isInstantiated());
 
     SkIPoint16 location;
     if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) {
@@ -112,21 +131,19 @@
     return true;
 }
 
-sk_sp<GrRenderTargetContext> GrCCAtlas::initInternalTextureProxy(
-        GrOnFlushResourceProvider* onFlushRP, GrPixelConfig config) {
-    SkASSERT(!fTextureProxy);
-    // Caller should have cropped any paths to the destination render target instead of asking for
-    // an atlas larger than maxRenderTargetSize.
-    SkASSERT(SkTMax(fHeight, fWidth) <= fMaxTextureSize);
+void GrCCAtlas::setUserBatchID(int id) {
+    // This can't be called anymore once makeRenderTargetContext() has been called.
+    SkASSERT(!fTextureProxy->priv().isInstantiated());
+    fUserBatchID = id;
+}
+
+sk_sp<GrRenderTargetContext> GrCCAtlas::makeRenderTargetContext(
+        GrOnFlushResourceProvider* onFlushRP) {
+    SkASSERT(!fTextureProxy->priv().isInstantiated());  // This method should only be called once.
     SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
 
-    GrSurfaceDesc desc;
-    desc.fFlags = kRenderTarget_GrSurfaceFlag;
-    desc.fWidth = fWidth;
-    desc.fHeight = fHeight;
-    desc.fConfig = config;
     sk_sp<GrRenderTargetContext> rtc =
-            onFlushRP->makeRenderTargetContext(desc, kTextureOrigin, nullptr, nullptr);
+            onFlushRP->makeRenderTargetContext(fTextureProxy, nullptr, nullptr);
     if (!rtc) {
         SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
                  fWidth, fHeight);
@@ -135,20 +152,18 @@
 
     SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
     rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
-
-    fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
     return rtc;
 }
 
-GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* offset) {
+GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) {
     GrCCAtlas* retiredAtlas = nullptr;
-    if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, offset)) {
+    if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) {
         // The retired atlas is out of room and can't grow any bigger.
         retiredAtlas = !fAtlases.empty() ? &fAtlases.back() : nullptr;
-        fAtlases.emplace_back(fSpecs);
+        fAtlases.emplace_back(fPixelConfig, fSpecs, *fCaps);
         SkASSERT(devIBounds.width() <= fSpecs.fMinWidth);
         SkASSERT(devIBounds.height() <= fSpecs.fMinHeight);
-        SkAssertResult(fAtlases.back().addRect(devIBounds, offset));
+        SkAssertResult(fAtlases.back().addRect(devIBounds, devToAtlasOffset));
     }
     return retiredAtlas;
 }
diff --git a/src/gpu/ccpr/GrCCAtlas.h b/src/gpu/ccpr/GrCCAtlas.h
index d4a07f5..6d82728 100644
--- a/src/gpu/ccpr/GrCCAtlas.h
+++ b/src/gpu/ccpr/GrCCAtlas.h
@@ -43,9 +43,11 @@
         void accountForSpace(int width, int height);
     };
 
-    GrCCAtlas(const Specs&);
+    GrCCAtlas(GrPixelConfig, const Specs&, const GrCaps&);
     ~GrCCAtlas();
 
+    GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
+
     // Attempts to add a rect to the atlas. If successful, returns the integer offset from
     // device-space pixels where the path will be drawn, to atlas pixels where its mask resides.
     bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset);
@@ -53,15 +55,13 @@
 
     // This is an optional space for the caller to jot down which user-defined batch to use when
     // they render the content of this atlas.
-    void setUserBatchID(int id) { SkASSERT(!fTextureProxy); fUserBatchID = id; }
+    void setUserBatchID(int id);
     int getUserBatchID() const { return fUserBatchID; }
 
-    // Creates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext that
-    // the caller may use to render the content. After this call, it is no longer valid to call
-    // addRect() or setUserBatchID().
-    sk_sp<GrRenderTargetContext> initInternalTextureProxy(GrOnFlushResourceProvider*,
-                                                          GrPixelConfig);
-    GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
+    // Instantiates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext
+    // that the caller may use to render the content. After this call, it is no longer valid to call
+    // addRect(), setUserBatchID(), or this method again.
+    sk_sp<GrRenderTargetContext> makeRenderTargetContext(GrOnFlushResourceProvider*);
 
 private:
     class Node;
@@ -83,7 +83,8 @@
  */
 class GrCCAtlasStack {
 public:
-    GrCCAtlasStack(const GrCCAtlas::Specs& specs) : fSpecs(specs) {}
+    GrCCAtlasStack(GrPixelConfig pixelConfig, const GrCCAtlas::Specs& specs, const GrCaps* caps)
+            : fPixelConfig(pixelConfig), fSpecs(specs), fCaps(caps) {}
 
     bool empty() const { return fAtlases.empty(); }
     const GrCCAtlas& front() const { SkASSERT(!this->empty()); return fAtlases.front(); }
@@ -106,10 +107,12 @@
     // atlas, so it was retired and a new one was added to the stack. The return value is the
     // newly-retired atlas. The caller should call setUserBatchID() on the retired atlas before
     // moving on.
-    GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* offset);
+    GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset);
 
 private:
+    const GrPixelConfig fPixelConfig;
     const GrCCAtlas::Specs fSpecs;
+    const GrCaps* const fCaps;
     GrSTAllocator<4, GrCCAtlas> fAtlases;
 };
 
diff --git a/src/gpu/ccpr/GrCCClipPath.cpp b/src/gpu/ccpr/GrCCClipPath.cpp
index 77674e4..61d58d4 100644
--- a/src/gpu/ccpr/GrCCClipPath.cpp
+++ b/src/gpu/ccpr/GrCCClipPath.cpp
@@ -12,12 +12,11 @@
 #include "GrTexture.h"
 #include "ccpr/GrCCPerFlushResources.h"
 
-void GrCCClipPath::init(GrProxyProvider* proxyProvider,
-                        const SkPath& deviceSpacePath, const SkIRect& accessRect,
-                        int rtWidth, int rtHeight) {
+void GrCCClipPath::init(const SkPath& deviceSpacePath, const SkIRect& accessRect, int rtWidth,
+                        int rtHeight, const GrCaps& caps) {
     SkASSERT(!this->isInitialized());
 
-    fAtlasLazyProxy = proxyProvider->createFullyLazyProxy(
+    fAtlasLazyProxy = GrProxyProvider::MakeFullyLazyProxy(
             [this](GrResourceProvider* resourceProvider) {
                 if (!resourceProvider) {
                     return sk_sp<GrTexture>();
@@ -41,7 +40,8 @@
 
                 return sk_ref_sp(textureProxy->priv().peekTexture());
             },
-            GrProxyProvider::Renderable::kYes, kTopLeft_GrSurfaceOrigin, kAlpha_half_GrPixelConfig);
+            GrProxyProvider::Renderable::kYes, kTopLeft_GrSurfaceOrigin, kAlpha_half_GrPixelConfig,
+            caps);
 
     fDeviceSpacePath = deviceSpacePath;
     fDeviceSpacePath.getBounds().roundOut(&fPathDevIBounds);
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index 16a2c66..c38dd76 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -124,7 +124,8 @@
         }
         if (currentAtlas != atlas) {
             if (currentAtlas) {
-                this->addAtlasBatch(currentAtlas, resources->nextPathInstanceIdx());
+                this->recordInstanceRange(currentAtlas->textureProxy(),
+                                          resources->nextPathInstanceIdx());
             }
             currentAtlas = atlas;
         }
@@ -135,7 +136,7 @@
 
     SkASSERT(resources->nextPathInstanceIdx() == fBaseInstance + fNumDraws - fNumSkippedInstances);
     if (currentAtlas) {
-        this->addAtlasBatch(currentAtlas, resources->nextPathInstanceIdx());
+        this->recordInstanceRange(currentAtlas->textureProxy(), resources->nextPathInstanceIdx());
     }
 }
 
@@ -159,20 +160,16 @@
 
     int baseInstance = fBaseInstance;
 
-    for (int i = 0; i < fAtlasBatches.count(); baseInstance = fAtlasBatches[i++].fEndInstanceIdx) {
-        const AtlasBatch& batch = fAtlasBatches[i];
-        SkASSERT(batch.fEndInstanceIdx > baseInstance);
+    for (const InstanceRange& range : fInstanceRanges) {
+        SkASSERT(range.fEndInstanceIdx > baseInstance);
 
-        if (!batch.fAtlas->textureProxy()) {
-            continue;  // Atlas failed to allocate.
-        }
-
-        GrCCPathProcessor pathProc(flushState->resourceProvider(),
-                                   sk_ref_sp(batch.fAtlas->textureProxy()),
+        GrCCPathProcessor pathProc(flushState->resourceProvider(), sk_ref_sp(range.fAtlasProxy),
                                    fViewMatrixIfUsingLocalCoords);
         pathProc.drawPaths(flushState, pipeline, resources->indexBuffer(),
                            resources->vertexBuffer(), resources->instanceBuffer(),
-                           baseInstance, batch.fEndInstanceIdx, this->bounds());
+                           baseInstance, range.fEndInstanceIdx, this->bounds());
+
+        baseInstance = range.fEndInstanceIdx;
     }
 
     SkASSERT(baseInstance == fBaseInstance + fNumDraws - fNumSkippedInstances);
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h
index 87cd50e..071a21a 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.h
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.h
@@ -54,16 +54,16 @@
     GrCCDrawPathsOp(const SkIRect& looseClippedIBounds, const SkMatrix&, const SkPath&,
                     const SkRect& devBounds, GrPaint&&);
 
-    struct AtlasBatch {
-        const GrCCAtlas* fAtlas;
+    struct InstanceRange {
+        const GrTextureProxy* fAtlasProxy;
         int fEndInstanceIdx;
     };
 
-    void addAtlasBatch(const GrCCAtlas* atlas, int endInstanceIdx) {
+    void recordInstanceRange(const GrTextureProxy* atlasProxy, int endInstanceIdx) {
         SkASSERT(endInstanceIdx > fBaseInstance);
-        SkASSERT(fAtlasBatches.empty() ||
-                 endInstanceIdx > fAtlasBatches.back().fEndInstanceIdx);
-        fAtlasBatches.push_back() = {atlas, endInstanceIdx};
+        SkASSERT(fInstanceRanges.empty() ||
+                 endInstanceIdx > fInstanceRanges.back().fEndInstanceIdx);
+        fInstanceRanges.push_back() = {atlasProxy, endInstanceIdx};
     }
 
     const SkMatrix fViewMatrixIfUsingLocalCoords;
@@ -84,7 +84,7 @@
     GrProcessorSet fProcessors;
 
     int fBaseInstance;
-    SkSTArray<1, AtlasBatch, true> fAtlasBatches;
+    SkSTArray<1, InstanceRange, true> fInstanceRanges;
     SkDEBUGCODE(int fNumSkippedInstances = 0);
 };
 
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index 5b3dec0..4738a25 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -69,7 +69,7 @@
 GrCCPerFlushResources::GrCCPerFlushResources(GrOnFlushResourceProvider* onFlushRP,
                                              const GrCCPerFlushResourceSpecs& specs)
         : fPathParser(specs.fNumRenderedPaths + specs.fNumClipPaths, specs.fParsingPathStats)
-        , fAtlasStack(specs.fAtlasSpecs)
+        , fAtlasStack(kAlpha_half_GrPixelConfig, specs.fAtlasSpecs, onFlushRP->caps())
         , fIndexBuffer(GrCCPathProcessor::FindIndexBuffer(onFlushRP))
         , fVertexBuffer(GrCCPathProcessor::FindVertexBuffer(onFlushRP))
         , fInstanceBuffer(onFlushRP->makeBuffer(kVertex_GrBufferType,
@@ -170,7 +170,7 @@
 
     // Render the atlas(es).
     for (GrCCAtlasStack::Iter atlas(fAtlasStack); atlas.next();) {
-        if (auto rtc = atlas->initInternalTextureProxy(onFlushRP, kAlpha_half_GrPixelConfig)) {
+        if (auto rtc = atlas->makeRenderTargetContext(onFlushRP)) {
             auto op = RenderAtlasOp::Make(rtc->surfPriv().getContext(), sk_ref_sp(this),
                                           atlas->getUserBatchID(), atlas->drawBounds());
             rtc->addDrawOp(GrNoClip(), std::move(op));
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index 727649b..eaab184 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -147,9 +147,8 @@
 }
 
 std::unique_ptr<GrFragmentProcessor> GrCoverageCountingPathRenderer::makeClipProcessor(
-        GrProxyProvider* proxyProvider,
-        uint32_t opListID, const SkPath& deviceSpacePath, const SkIRect& accessRect,
-        int rtWidth, int rtHeight) {
+        uint32_t opListID, const SkPath& deviceSpacePath, const SkIRect& accessRect, int rtWidth,
+        int rtHeight, const GrCaps& caps) {
     using MustCheckBounds = GrCCClipProcessor::MustCheckBounds;
 
     SkASSERT(!fFlushing);
@@ -162,11 +161,11 @@
         if (SkTMax(pathDevBounds.height(), pathDevBounds.width()) > kPathCropThreshold) {
             // The path is too large. Crop it or analytic AA can run out of fp32 precision.
             SkPath croppedPath;
-            int maxRTSize = proxyProvider->caps()->maxRenderTargetSize();
+            int maxRTSize = caps.maxRenderTargetSize();
             crop_path(deviceSpacePath, SkIRect::MakeWH(maxRTSize, maxRTSize), &croppedPath);
-            clipPath.init(proxyProvider, croppedPath, accessRect, rtWidth, rtHeight);
+            clipPath.init(croppedPath, accessRect, rtWidth, rtHeight, caps);
         } else {
-            clipPath.init(proxyProvider, deviceSpacePath, accessRect, rtWidth, rtHeight);
+            clipPath.init(deviceSpacePath, accessRect, rtWidth, rtHeight, caps);
         }
     } else {
         clipPath.addAccess(accessRect);
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h
index abc824b..8cb9713 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h
@@ -60,10 +60,10 @@
     CanDrawPath onCanDrawPath(const CanDrawPathArgs& args) const override;
     bool onDrawPath(const DrawPathArgs&) override;
 
-    std::unique_ptr<GrFragmentProcessor> makeClipProcessor(GrProxyProvider*, uint32_t oplistID,
+    std::unique_ptr<GrFragmentProcessor> makeClipProcessor(uint32_t oplistID,
                                                            const SkPath& deviceSpacePath,
-                                                           const SkIRect& accessRect,
-                                                           int rtWidth, int rtHeight);
+                                                           const SkIRect& accessRect, int rtWidth,
+                                                           int rtHeight, const GrCaps&);
 
     // GrOnFlushCallbackObject overrides.
     void preFlush(GrOnFlushResourceProvider*, const uint32_t* opListIDs, int numOpListIDs,