Reland "ccpr: Rework the path cache to support sporadic flushing"

This is a reland of d6fa45472cb82b7d8e58d0437f7723c672488b8b

Original change's description:
> ccpr: Rework the path cache to support sporadic flushing
> 
> Removes the notion of a stashed atlas that we store from the previous
> flush. Now we just cache every atlas we ever render. Cached atlases
> can either be 16-bit or 8-bit.
> 
> The "reuse" and "animation" cases should both behave exactly the same
> as before: Where before we would copy from the stashed atlas to 8-bit
> atlases, we now copy from a cached 16-bit atlas and then invalidate
> it. Where before we would recycle the stashed atlas's backing texture
> object, we now recycle this same texture object from an invalidated
> 16-bit cached atlas.
> 
> The main difference is that cases like tiled rendering now work. If
> you draw your whole scene in one flush, you still get one big 16-bit
> cached atlas, just like the "stashed atlas" implementation. But if you
> draw your scene in tiles, you now get lots of little cached 16-bit
> atlases, which can be reused and eventually copied to 8-bit atlases.
> 
> Bug: skia:8462
> Change-Id: Ibae65febb948230aaaf1f1361eef9c8f06ebef18
> Reviewed-on: https://skia-review.googlesource.com/c/179991
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Robert Phillips <robertphillips@google.com>

Bug: skia:8462
Change-Id: I2f64b0c37e2cd644a202dfc786366dda5d238391
Reviewed-on: https://skia-review.googlesource.com/c/181450
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.h b/src/gpu/ccpr/GrCCPerFlushResources.h
index 132068f..f363c16 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.h
+++ b/src/gpu/ccpr/GrCCPerFlushResources.h
@@ -14,6 +14,7 @@
 #include "ccpr/GrCCStroker.h"
 #include "ccpr/GrCCPathProcessor.h"
 
+class GrCCPathCache;
 class GrCCPathCacheEntry;
 class GrOnFlushResourceProvider;
 class GrShape;
@@ -53,7 +54,8 @@
         return 0 == fNumCachedPaths + fNumCopiedPaths[kFillIdx] + fNumCopiedPaths[kStrokeIdx] +
                     fNumRenderedPaths[kFillIdx] + fNumRenderedPaths[kStrokeIdx] + fNumClipPaths;
     }
-    void convertCopiesToRenders();
+    // Converts the copies to normal cached draws.
+    void cancelCopies();
 };
 
 /**
@@ -67,22 +69,19 @@
 
     bool isMapped() const { return SkToBool(fPathInstanceData); }
 
-    // Copies a path out of the the previous flush's stashed mainline coverage count atlas, and into
-    // a cached, 8-bit, literal-coverage atlas. The actual source texture to copy from will be
-    // provided at the time finalize() is called.
-    GrCCAtlas* copyPathToCachedAtlas(const GrCCPathCacheEntry&, GrCCPathProcessor::DoEvenOddFill,
-                                     SkIVector* newAtlasOffset);
+    // Copies a coverage-counted path out of the given texture proxy, and into a cached, 8-bit,
+    // literal coverage atlas. Updates the cache entry to reference the new atlas.
+    void upgradeEntryToLiteralCoverageAtlas(GrCCPathCache*, GrOnFlushResourceProvider*,
+                                            GrCCPathCacheEntry*, GrCCPathProcessor::DoEvenOddFill);
 
     // These two methods render a path into a temporary coverage count atlas. See
-    // GrCCPathProcessor::Instance for a description of the outputs. The returned atlases are
-    // "const" to prevent the caller from assigning a unique key.
+    // GrCCPathProcessor::Instance for a description of the outputs.
     //
     // strokeDevWidth must be 0 for fills, 1 for hairlines, or the stroke width in device-space
     // pixels for non-hairline strokes (implicitly requiring a rigid-body transform).
-    const GrCCAtlas* renderShapeInAtlas(const SkIRect& clipIBounds, const SkMatrix&, const GrShape&,
-                                        float strokeDevWidth, SkRect* devBounds,
-                                        SkRect* devBounds45, SkIRect* devIBounds,
-                                        SkIVector* devToAtlasOffset);
+    GrCCAtlas* renderShapeInAtlas(const SkIRect& clipIBounds, const SkMatrix&, const GrShape&,
+                                  float strokeDevWidth, SkRect* devBounds, SkRect* devBounds45,
+                                  SkIRect* devIBounds, SkIVector* devToAtlasOffset);
     const GrCCAtlas* renderDeviceSpacePathInAtlas(const SkIRect& clipIBounds, const SkPath& devPath,
                                                   const SkIRect& devPathIBounds,
                                                   SkIVector* devToAtlasOffset);
@@ -100,11 +99,8 @@
         return fPathInstanceData[fNextPathInstanceIdx++];
     }
 
-    // Finishes off the GPU buffers and renders the atlas(es). 'stashedAtlasProxy', if provided, is
-    // the mainline coverage count atlas from the previous flush. It will be used as the source
-    // texture for any copies setup by copyStashedPathToAtlas().
-    bool finalize(GrOnFlushResourceProvider*, sk_sp<GrTextureProxy> stashedAtlasProxy,
-                  SkTArray<sk_sp<GrRenderTargetContext>>* out);
+    // Finishes off the GPU buffers and renders the atlas(es).
+    bool finalize(GrOnFlushResourceProvider*, SkTArray<sk_sp<GrRenderTargetContext>>* out);
 
     // Accessors used by draw calls, once the resources have been finalized.
     const GrCCFiller& filler() const { SkASSERT(!this->isMapped()); return fFiller; }
@@ -113,23 +109,9 @@
     const GrBuffer* vertexBuffer() const { SkASSERT(!this->isMapped()); return fVertexBuffer.get();}
     GrBuffer* instanceBuffer() const { SkASSERT(!this->isMapped()); return fInstanceBuffer.get(); }
 
-    // Returns the mainline coverage count atlas that the client may stash for next flush, if any.
-    // The caller is responsible to call getOrAssignUniqueKey() on this atlas if they wish to
-    // actually stash it in order to copy paths into cached atlases.
-    GrCCAtlas* nextAtlasToStash() {
-        return fRenderedAtlasStack.empty() ? nullptr : &fRenderedAtlasStack.front();
-    }
-
-    // Returs true if the client has called getOrAssignUniqueKey() on our nextAtlasToStash().
-    bool hasStashedAtlas() const {
-        return !fRenderedAtlasStack.empty() && fRenderedAtlasStack.front().uniqueKey().isValid();
-    }
-    const GrUniqueKey& stashedAtlasKey() const  {
-        SkASSERT(this->hasStashedAtlas());
-        return fRenderedAtlasStack.front().uniqueKey();
-    }
-
 private:
+    void recordCopyPathInstance(const GrCCPathCacheEntry&, const SkIVector& newAtlasOffset,
+                                GrCCPathProcessor::DoEvenOddFill, sk_sp<GrTextureProxy> srcProxy);
     bool placeRenderedPathInAtlas(const SkIRect& clipIBounds, const SkIRect& pathIBounds,
                                   GrScissorTest*, SkIRect* clippedPathIBounds,
                                   SkIVector* devToAtlasOffset);
@@ -149,6 +131,30 @@
     SkDEBUGCODE(int fEndCopyInstance);
     int fNextPathInstanceIdx;
     SkDEBUGCODE(int fEndPathInstance);
+
+    // Represents a range of copy-path instances that all share the same source proxy. (i.e. Draw
+    // instances that copy a path mask from a 16-bit coverage count atlas into an 8-bit literal
+    // coverage atlas.)
+    struct CopyPathRange {
+        CopyPathRange() = default;
+        CopyPathRange(sk_sp<GrTextureProxy> srcProxy, int count)
+                : fSrcProxy(std::move(srcProxy)), fCount(count) {}
+        sk_sp<GrTextureProxy> fSrcProxy;
+        int fCount;
+    };
+
+    SkSTArray<4, CopyPathRange> fCopyPathRanges;
+    int fCurrCopyAtlasRangesIdx = 0;
+
+    // This is a list of coverage count atlas textures that have been invalidated due to us copying
+    // their paths into new 8-bit literal coverage atlases. Since copying is finished by the time
+    // we begin rendering new atlases, we can recycle these textures for the rendered atlases rather
+    // than allocating new texture objects upon instantiation.
+    SkSTArray<2, sk_sp<GrTexture>> fRecyclableAtlasTextures;
+
+public:
+    const GrTexture* testingOnly_frontCopyAtlasTexture() const;
+    const GrTexture* testingOnly_frontRenderedAtlasTexture() const;
 };
 
 inline void GrCCRenderedPathStats::statPath(const SkPath& path) {