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/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index c1384fe..ba16f58 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrCCDrawPathsOp.h"
+
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrMemoryPool.h"
@@ -157,13 +158,6 @@
 #endif
 }
 
-GrCCDrawPathsOp::SingleDraw::~SingleDraw() {
-    if (fCacheEntry) {
-        // All currFlushAtlas references must be reset back to null before the flush is finished.
-        fCacheEntry->setCurrFlushAtlas(nullptr);
-    }
-}
-
 GrDrawOp::RequiresDstTexture GrCCDrawPathsOp::finalize(const GrCaps& caps,
                                                        const GrAppliedClip* clip) {
     SkASSERT(1 == fNumDraws);  // There should only be one single path draw in this Op right now.
@@ -233,10 +227,10 @@
 
 void GrCCDrawPathsOp::accountForOwnPaths(GrCCPathCache* pathCache,
                                          GrOnFlushResourceProvider* onFlushRP,
-                                         const GrUniqueKey& stashedAtlasKey,
                                          GrCCPerFlushResourceSpecs* specs) {
     using CreateIfAbsent = GrCCPathCache::CreateIfAbsent;
     using MaskTransform = GrCCPathCache::MaskTransform;
+    using CoverageType = GrCCAtlas::CoverageType;
 
     for (SingleDraw& draw : fDraws) {
         SkPath path;
@@ -247,41 +241,32 @@
         if (pathCache) {
             MaskTransform m(draw.fMatrix, &draw.fCachedMaskShift);
             bool canStashPathMask = draw.fMaskVisibility >= Visibility::kMostlyComplete;
-            draw.fCacheEntry = pathCache->find(draw.fShape, m, CreateIfAbsent(canStashPathMask));
+            draw.fCacheEntry =
+                    pathCache->find(onFlushRP, draw.fShape, m, CreateIfAbsent(canStashPathMask));
         }
 
-        if (auto cacheEntry = draw.fCacheEntry.get()) {
-            SkASSERT(!cacheEntry->currFlushAtlas());  // Shouldn't be set until setupResources().
-
-            if (cacheEntry->atlasKey().isValid()) {
-                // Does the path already exist in a cached atlas?
-                if (cacheEntry->hasCachedAtlas() &&
-                    (draw.fCachedAtlasProxy = onFlushRP->findOrCreateProxyByUniqueKey(
-                                                     cacheEntry->atlasKey(),
-                                                     GrCCAtlas::kTextureOrigin))) {
+        if (draw.fCacheEntry) {
+            if (const GrCCCachedAtlas* cachedAtlas = draw.fCacheEntry->cachedAtlas()) {
+                SkASSERT(cachedAtlas->getOnFlushProxy());
+                if (CoverageType::kA8_LiteralCoverage == cachedAtlas->coverageType()) {
                     ++specs->fNumCachedPaths;
-                    continue;
-                }
-
-                // Does the path exist in the atlas that we stashed away from last flush? If so we
-                // can copy it into a new 8-bit atlas and keep it in the resource cache.
-                if (stashedAtlasKey.isValid() && stashedAtlasKey == cacheEntry->atlasKey()) {
-                    SkASSERT(!cacheEntry->hasCachedAtlas());
+                } else {
+                    // Suggest that this path be copied to a literal coverage atlas, to save memory.
+                    // (The client may decline this copy via DoCopiesToA8Coverage::kNo.)
                     int idx = (draw.fShape.style().strokeRec().isFillStyle())
                             ? GrCCPerFlushResourceSpecs::kFillIdx
                             : GrCCPerFlushResourceSpecs::kStrokeIdx;
                     ++specs->fNumCopiedPaths[idx];
                     specs->fCopyPathStats[idx].statPath(path);
-                    specs->fCopyAtlasSpecs.accountForSpace(cacheEntry->width(),
-                                                           cacheEntry->height());
-                    continue;
+                    specs->fCopyAtlasSpecs.accountForSpace(
+                            draw.fCacheEntry->width(), draw.fCacheEntry->height());
+                    draw.fDoCopyToA8Coverage = true;
                 }
-
-                // Whatever atlas the path used to reside in, it no longer exists.
-                cacheEntry->resetAtlasKeyAndInfo();
+                continue;
             }
 
-            if (Visibility::kMostlyComplete == draw.fMaskVisibility && cacheEntry->hitCount() > 1) {
+            if (Visibility::kMostlyComplete == draw.fMaskVisibility &&
+                    draw.fCacheEntry->hitCount() > 1) {
                 int shapeSize = SkTMax(draw.fShapeConservativeIBounds.height(),
                                        draw.fShapeConservativeIBounds.width());
                 if (shapeSize <= onFlushRP->caps()->maxRenderTargetSize()) {
@@ -303,8 +288,9 @@
     }
 }
 
-void GrCCDrawPathsOp::setupResources(GrOnFlushResourceProvider* onFlushRP,
-                                     GrCCPerFlushResources* resources, DoCopiesToCache doCopies) {
+void GrCCDrawPathsOp::setupResources(
+        GrCCPathCache* pathCache, GrOnFlushResourceProvider* onFlushRP,
+        GrCCPerFlushResources* resources, DoCopiesToA8Coverage doCopies) {
     using DoEvenOddFill = GrCCPathProcessor::DoEvenOddFill;
     SkASSERT(fNumDraws > 0);
     SkASSERT(-1 == fBaseInstance);
@@ -321,51 +307,29 @@
 
         if (auto cacheEntry = draw.fCacheEntry.get()) {
             // Does the path already exist in a cached atlas texture?
-            if (auto proxy = draw.fCachedAtlasProxy.get()) {
-                SkASSERT(!cacheEntry->currFlushAtlas());
-                this->recordInstance(proxy, resources->nextPathInstanceIdx());
+            if (cacheEntry->cachedAtlas()) {
+                SkASSERT(cacheEntry->cachedAtlas()->getOnFlushProxy());
+                if (DoCopiesToA8Coverage::kYes == doCopies && draw.fDoCopyToA8Coverage) {
+                    resources->upgradeEntryToLiteralCoverageAtlas(pathCache, onFlushRP, cacheEntry,
+                                                                  doEvenOddFill);
+                    SkASSERT(cacheEntry->cachedAtlas());
+                    SkASSERT(GrCCAtlas::CoverageType::kA8_LiteralCoverage
+                                     == cacheEntry->cachedAtlas()->coverageType());
+                    SkASSERT(cacheEntry->cachedAtlas()->getOnFlushProxy());
+                }
+                this->recordInstance(cacheEntry->cachedAtlas()->getOnFlushProxy(),
+                                     resources->nextPathInstanceIdx());
                 // TODO4F: Preserve float colors
                 resources->appendDrawPathInstance().set(*cacheEntry, draw.fCachedMaskShift,
                                                         draw.fColor.toBytes_RGBA());
                 continue;
             }
-
-            // Have we already encountered this path during the flush? (i.e. was the same SkPath
-            // drawn more than once during the same flush, with a compatible matrix?)
-            if (auto atlas = cacheEntry->currFlushAtlas()) {
-                this->recordInstance(atlas->textureProxy(), resources->nextPathInstanceIdx());
-                // TODO4F: Preserve float colors
-                resources->appendDrawPathInstance().set(
-                        *cacheEntry, draw.fCachedMaskShift, draw.fColor.toBytes_RGBA(),
-                        cacheEntry->hasCachedAtlas() ? DoEvenOddFill::kNo : doEvenOddFill);
-                continue;
-            }
-
-            // If the cache entry still has a valid atlas key at this point, it means the path
-            // exists in the atlas that we stashed away from last flush. Copy it into a permanent
-            // 8-bit atlas in the resource cache.
-            if (DoCopiesToCache::kYes == doCopies && cacheEntry->atlasKey().isValid()) {
-                SkIVector newOffset;
-                GrCCAtlas* atlas =
-                        resources->copyPathToCachedAtlas(*cacheEntry, doEvenOddFill, &newOffset);
-                cacheEntry->updateToCachedAtlas(
-                        atlas->getOrAssignUniqueKey(onFlushRP), newOffset,
-                        atlas->refOrMakeCachedAtlasInfo(onFlushRP->contextUniqueID()));
-                this->recordInstance(atlas->textureProxy(), resources->nextPathInstanceIdx());
-                // TODO4F: Preserve float colors
-                resources->appendDrawPathInstance().set(*cacheEntry, draw.fCachedMaskShift,
-                                                        draw.fColor.toBytes_RGBA());
-                // Remember this atlas in case we encounter the path again during the same flush.
-                cacheEntry->setCurrFlushAtlas(atlas);
-                continue;
-            }
         }
 
-        // Render the raw path into a coverage count atlas. renderPathInAtlas() gives us two tight
+        // Render the raw path into a coverage count atlas. renderShapeInAtlas() gives us two tight
         // bounding boxes: One in device space, as well as a second one rotated an additional 45
         // degrees. The path vertex shader uses these two bounding boxes to generate an octagon that
         // circumscribes the path.
-        SkASSERT(!draw.fCachedAtlasProxy);
         SkRect devBounds, devBounds45;
         SkIRect devIBounds;
         SkIVector devToAtlasOffset;
@@ -380,7 +344,7 @@
             // If we have a spot in the path cache, try to make a note of where this mask is so we
             // can reuse it in the future.
             if (auto cacheEntry = draw.fCacheEntry.get()) {
-                SkASSERT(!cacheEntry->hasCachedAtlas());
+                SkASSERT(!cacheEntry->cachedAtlas());
 
                 if (Visibility::kComplete != draw.fMaskVisibility || cacheEntry->hitCount() <= 1) {
                     // Don't cache a path mask unless it's completely visible with a hit count > 1.
@@ -390,19 +354,9 @@
                     continue;
                 }
 
-                if (resources->nextAtlasToStash() != atlas) {
-                    // This mask does not belong to the atlas that will be stashed for next flush.
-                    continue;
-                }
-
-                const GrUniqueKey& atlasKey =
-                        resources->nextAtlasToStash()->getOrAssignUniqueKey(onFlushRP);
-                cacheEntry->initAsStashedAtlas(atlasKey, devToAtlasOffset, devBounds, devBounds45,
-                                               devIBounds, draw.fCachedMaskShift);
-                // Remember this atlas in case we encounter the path again during the same flush.
-                cacheEntry->setCurrFlushAtlas(atlas);
+                cacheEntry->setCoverageCountAtlas(onFlushRP, atlas, devToAtlasOffset, devBounds,
+                                                  devBounds45, devIBounds, draw.fCachedMaskShift);
             }
-            continue;
         }
     }