Make the GrSmallPathAtlasMgr a flush-time object

This will allow the small path renderer to be used w/ DDLs.

This is broken out of the omnibus CL:

https://skia-review.googlesource.com/c/skia/+/307776 (Split the small path renderer into record-time and flush-time pieces)

Bug: 1108408
Change-Id: I64cc6ff677d0aead7cf2f097c0e7fbb15b49d49d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/309304
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp
index 4ae1831..6f04a5f 100644
--- a/src/gpu/GrDirectContext.cpp
+++ b/src/gpu/GrDirectContext.cpp
@@ -59,16 +59,25 @@
 
 void GrDirectContext::abandonContext() {
     INHERITED::abandonContext();
+    if (fSmallPathAtlasMgr) {
+        fSmallPathAtlasMgr->reset();
+    }
     fAtlasManager->freeAll();
 }
 
 void GrDirectContext::releaseResourcesAndAbandonContext() {
     INHERITED::releaseResourcesAndAbandonContext();
+    if (fSmallPathAtlasMgr) {
+        fSmallPathAtlasMgr->reset();
+    }
     fAtlasManager->freeAll();
 }
 
 void GrDirectContext::freeGpuResources() {
     this->flushAndSubmit();
+    if (fSmallPathAtlasMgr) {
+        fSmallPathAtlasMgr->reset();
+    }
     fAtlasManager->freeAll();
 
     INHERITED::freeGpuResources();
@@ -115,8 +124,17 @@
 }
 
 GrSmallPathAtlasMgr* GrDirectContext::onGetSmallPathAtlasMgr() {
-    // The small path renderer atlas will be created here
-    return nullptr;
+    if (!fSmallPathAtlasMgr) {
+        fSmallPathAtlasMgr = std::make_unique<GrSmallPathAtlasMgr>();
+
+        this->priv().addOnFlushCallbackObject(fSmallPathAtlasMgr.get());
+    }
+
+    if (!fSmallPathAtlasMgr->initAtlas(this->proxyProvider(), this->caps())) {
+        return nullptr;
+    }
+
+    return fSmallPathAtlasMgr.get();
 }
 
 #ifdef SK_GL
diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp
index 337f7cd..ed7d532 100644
--- a/src/gpu/GrPathRendererChain.cpp
+++ b/src/gpu/GrPathRendererChain.cpp
@@ -59,9 +59,7 @@
         fChain.push_back(sk_make_sp<GrAALinearizingConvexPathRenderer>());
     }
     if (options.fGpuPathRenderers & GpuPathRenderers::kSmall) {
-        auto spr = sk_make_sp<GrSmallPathRenderer>();
-        spr->addToOnFlushCallbacks(context);
-        fChain.push_back(std::move(spr));
+        fChain.push_back(sk_make_sp<GrSmallPathRenderer>());
     }
     if (options.fGpuPathRenderers & GpuPathRenderers::kStencilAndCover) {
         auto direct = context->asDirectContext();
diff --git a/src/gpu/ops/GrSmallPathAtlasMgr.cpp b/src/gpu/ops/GrSmallPathAtlasMgr.cpp
index 7fbb232..ca9b5bf 100644
--- a/src/gpu/ops/GrSmallPathAtlasMgr.cpp
+++ b/src/gpu/ops/GrSmallPathAtlasMgr.cpp
@@ -30,6 +30,7 @@
         delete shapeData;
     }
 
+    fShapeList.reset();
     fShapeCache.reset();
 
 #ifdef DF_PATH_TRACKING
diff --git a/src/gpu/ops/GrSmallPathAtlasMgr.h b/src/gpu/ops/GrSmallPathAtlasMgr.h
index 7c5be41..17ab571 100644
--- a/src/gpu/ops/GrSmallPathAtlasMgr.h
+++ b/src/gpu/ops/GrSmallPathAtlasMgr.h
@@ -18,7 +18,12 @@
 class GrStyledShape;
 
 /**
- * This class manages the small path renderer's atlas.
+ * This class manages the small path renderer's atlas. It solely operates at flush time. Thus
+ * the small path renderer will generate ops at record time but the location of the ops' source
+ * data and even the number of proxies to be used will not be determined until the recorded
+ * DAGs/DDLs are (re)played.
+ *
+ * TODO: investigate fusing this class and the GrAtlasManager.
  */
 class GrSmallPathAtlasMgr : public GrOnFlushCallbackObject,
                             public GrDrawOpAtlas::EvictionCallback,
@@ -55,6 +60,10 @@
         }
     }
 
+    // This object has the same lifetime as the GrContext so we want it to survive freeGpuResources
+    // calls
+    bool retainOnFreeGpuResources() override { return true; }
+
     const GrSurfaceProxyView* getViews(int* numActiveProxies) {
         *numActiveProxies = fAtlas->numActivePages();
         return fAtlas->getViews();
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index 8410a25..95b40c6 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -40,14 +40,10 @@
 static constexpr SkScalar kMinSize = SK_ScalarHalf;
 static constexpr SkScalar kMaxSize = 2*kMaxMIP;
 
-GrSmallPathRenderer::GrSmallPathRenderer() : fAtlasMgr(new GrSmallPathAtlasMgr) {}
+GrSmallPathRenderer::GrSmallPathRenderer() {}
 
 GrSmallPathRenderer::~GrSmallPathRenderer() {}
 
-void GrSmallPathRenderer::addToOnFlushCallbacks(GrRecordingContext* rContext) {
-    rContext->priv().addOnFlushCallbackObject(fAtlasMgr.get());
-}
-
 GrPathRenderer::CanDrawPath GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     if (!args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
         return CanDrawPath::kNo;
@@ -105,15 +101,14 @@
                                           GrPaint&& paint,
                                           const GrStyledShape& shape,
                                           const SkMatrix& viewMatrix,
-                                          GrSmallPathAtlasMgr* atlasMgr,
                                           bool gammaCorrect,
                                           const GrUserStencilSettings* stencilSettings) {
         return Helper::FactoryHelper<SmallPathOp>(context, std::move(paint), shape, viewMatrix,
-                                                  atlasMgr, gammaCorrect, stencilSettings);
+                                                  gammaCorrect, stencilSettings);
     }
 
     SmallPathOp(Helper::MakeArgs helperArgs, const SkPMColor4f& color, const GrStyledShape& shape,
-                const SkMatrix& viewMatrix, GrSmallPathAtlasMgr* atlasMgr, bool gammaCorrect,
+                const SkMatrix& viewMatrix, bool gammaCorrect,
                 const GrUserStencilSettings* stencilSettings)
             : INHERITED(ClassID())
             , fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
@@ -132,7 +127,6 @@
 
         fShapes.emplace_back(Entry{color, shape, viewMatrix});
 
-        fAtlasMgr = atlasMgr;
         fGammaCorrect = gammaCorrect;
     }
 
@@ -197,6 +191,11 @@
     void onPrepareDraws(Target* target) override {
         int instanceCount = fShapes.count();
 
+        GrSmallPathAtlasMgr* atlasMgr = target->smallPathAtlasManager();
+        if (!atlasMgr) {
+            return;
+        }
+
         static constexpr int kMaxTextures = GrDistanceFieldPathGeoProc::kMaxTextures;
         static_assert(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures);
 
@@ -204,7 +203,7 @@
         flushInfo.fPrimProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
 
         int numActiveProxies;
-        const GrSurfaceProxyView* views = fAtlasMgr->getViews(&numActiveProxies);
+        const GrSurfaceProxyView* views = atlasMgr->getViews(&numActiveProxies);
         for (int i = 0; i < numActiveProxies; ++i) {
             // This op does not know its atlas proxies when it is added to a GrOpsTasks, so the
             // proxies don't get added during the visitProxies call. Thus we add them here.
@@ -322,39 +321,39 @@
                 int ceilDesiredDimension = SkScalarCeilToInt(desiredDimension);
 
                 // check to see if df path is cached
-                shapeData = fAtlasMgr->findOrCreate(args.fShape, ceilDesiredDimension);
+                shapeData = atlasMgr->findOrCreate(args.fShape, ceilDesiredDimension);
                 if (!shapeData->fAtlasLocator.plotLocator().isValid()) {
                     SkScalar scale = desiredDimension / maxDim;
 
                     if (!this->addDFPathToAtlas(target,
                                                 &flushInfo,
-                                                fAtlasMgr->atlas(),
+                                                atlasMgr->atlas(),
                                                 shapeData,
                                                 args.fShape,
                                                 ceilDesiredDimension,
                                                 scale)) {
-                        fAtlasMgr->deleteCacheEntry(shapeData);
+                        atlasMgr->deleteCacheEntry(shapeData);
                         continue;
                     }
                 }
             } else {
                 // check to see if bitmap path is cached
-                shapeData = fAtlasMgr->findOrCreate(args.fShape, args.fViewMatrix);
+                shapeData = atlasMgr->findOrCreate(args.fShape, args.fViewMatrix);
                 if (!shapeData->fAtlasLocator.plotLocator().isValid()) {
                     if (!this->addBMPathToAtlas(target,
                                                 &flushInfo,
-                                                fAtlasMgr->atlas(),
+                                                atlasMgr->atlas(),
                                                 shapeData,
                                                 args.fShape,
                                                 args.fViewMatrix)) {
-                        fAtlasMgr->deleteCacheEntry(shapeData);
+                        atlasMgr->deleteCacheEntry(shapeData);
                         continue;
                     }
                 }
             }
 
             auto uploadTarget = target->deferredUploadTarget();
-            fAtlasMgr->setUseToken(shapeData, uploadTarget->tokenTracker()->nextDrawToken());
+            atlasMgr->setUseToken(shapeData, uploadTarget->tokenTracker()->nextDrawToken());
 
             this->writePathVertices(vertices, GrVertexColor(args.fColor, fWideColor),
                                     args.fViewMatrix, shapeData);
@@ -367,6 +366,8 @@
     bool addToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo, GrDrawOpAtlas* atlas,
                     int width, int height, const void* image,
                     GrDrawOpAtlas::AtlasLocator* atlasLocator) const {
+        SkASSERT(atlas);
+
         auto resourceProvider = target->resourceProvider();
         auto uploadTarget = target->deferredUploadTarget();
 
@@ -389,6 +390,7 @@
     bool addDFPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo,
                           GrDrawOpAtlas* atlas, GrSmallPathShapeData* shapeData,
                           const GrStyledShape& shape, uint32_t dimension, SkScalar scale) const {
+        SkASSERT(atlas);
 
         const SkRect& bounds = shape.bounds();
 
@@ -487,6 +489,8 @@
     bool addBMPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo,
                           GrDrawOpAtlas* atlas, GrSmallPathShapeData* shapeData,
                           const GrStyledShape& shape, const SkMatrix& ctm) const {
+        SkASSERT(atlas);
+
         const SkRect& bounds = shape.bounds();
         if (bounds.isEmpty()) {
             return false;
@@ -580,12 +584,15 @@
     }
 
     void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
+        GrSmallPathAtlasMgr* atlasMgr = target->smallPathAtlasManager();
+        if (!atlasMgr) {
+            return;
+        }
 
         int numActiveProxies;
-        const GrSurfaceProxyView* views = fAtlasMgr->getViews(&numActiveProxies);
+        const GrSurfaceProxyView* views = atlasMgr->getViews(&numActiveProxies);
 
         GrGeometryProcessor* gp = flushInfo->fGeometryProcessor;
-
         if (gp->numTextureSamplers() != numActiveProxies) {
             for (int i = gp->numTextureSamplers(); i < numActiveProxies; ++i) {
                 flushInfo->fPrimProcProxies[i] = views[i].proxy();
@@ -678,7 +685,6 @@
 
     SkSTArray<1, Entry> fShapes;
     Helper fHelper;
-    GrSmallPathAtlasMgr* fAtlasMgr;
     bool fGammaCorrect;
     bool fWideColor;
 
@@ -689,18 +695,13 @@
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrSmallPathRenderer::onDrawPath");
 
-    const GrCaps* caps = args.fContext->priv().caps();
-
     // we've already bailed on inverse filled paths, so this is safe
     SkASSERT(!args.fShape->isEmpty());
     SkASSERT(args.fShape->hasUnstyledKey());
-    if (!fAtlasMgr->initAtlas(args.fContext->priv().proxyProvider(), caps)) {
-        return false;
-    }
 
     std::unique_ptr<GrDrawOp> op = SmallPathOp::Make(
             args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
-            fAtlasMgr.get(), args.fGammaCorrect, args.fUserStencilSettings);
+            args.fGammaCorrect, args.fUserStencilSettings);
     args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op));
 
     return true;
@@ -709,38 +710,19 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #if GR_TEST_UTILS
-
-struct GrSmallPathRenderer::PathTestStruct {
-    PathTestStruct() : fContextID(SK_InvalidGenID) {}
-    ~PathTestStruct() { }
-
-    uint32_t fContextID;
-    std::unique_ptr<GrSmallPathAtlasMgr> fAtlasMgr;
-};
-
 std::unique_ptr<GrDrawOp> GrSmallPathRenderer::createOp_TestingOnly(
                                                         GrRecordingContext* context,
                                                         GrPaint&& paint,
                                                         const GrStyledShape& shape,
                                                         const SkMatrix& viewMatrix,
-                                                        GrSmallPathAtlasMgr* atlasMgr,
                                                         bool gammaCorrect,
                                                         const GrUserStencilSettings* stencil) {
 
     return GrSmallPathRenderer::SmallPathOp::Make(context, std::move(paint), shape, viewMatrix,
-                                                  atlasMgr, gammaCorrect, stencil);
+                                                  gammaCorrect, stencil);
 }
 
 GR_DRAW_OP_TEST_DEFINE(SmallPathOp) {
-    static GrSmallPathRenderer::PathTestStruct gTestStruct;
-
-    if (context->priv().contextID() != gTestStruct.fContextID) {
-        gTestStruct.fContextID = context->priv().contextID();
-        gTestStruct.fAtlasMgr = std::make_unique<GrSmallPathAtlasMgr>();
-        gTestStruct.fAtlasMgr->initAtlas(context->priv().proxyProvider(),
-                                         context->priv().caps());
-    }
-
     SkMatrix viewMatrix = GrTest::TestMatrix(random);
     bool gammaCorrect = random->nextBool();
 
@@ -749,7 +731,6 @@
     return GrSmallPathRenderer::createOp_TestingOnly(
                                          context,
                                          std::move(paint), shape, viewMatrix,
-                                         gTestStruct.fAtlasMgr.get(),
                                          gammaCorrect,
                                          GrGetRandomStencil(random, context));
 }
diff --git a/src/gpu/ops/GrSmallPathRenderer.h b/src/gpu/ops/GrSmallPathRenderer.h
index e0a45a7..3fdba12 100644
--- a/src/gpu/ops/GrSmallPathRenderer.h
+++ b/src/gpu/ops/GrSmallPathRenderer.h
@@ -12,7 +12,6 @@
 
 class GrDrawOp;
 class GrRecordingContext;
-class GrSmallPathAtlasMgr;
 class GrStyledShape;
 
 class GrSmallPathRenderer : public GrPathRenderer {
@@ -22,16 +21,12 @@
 
     const char* name() const final { return "Small"; }
 
-    void addToOnFlushCallbacks(GrRecordingContext*);
-
     static std::unique_ptr<GrDrawOp> createOp_TestingOnly(GrRecordingContext*,
                                                           GrPaint&&,
                                                           const GrStyledShape&,
                                                           const SkMatrix& viewMatrix,
-                                                          GrSmallPathAtlasMgr*,
                                                           bool gammaCorrect,
                                                           const GrUserStencilSettings*);
-    struct PathTestStruct;
 
 private:
     class SmallPathOp;
@@ -44,8 +39,6 @@
 
     bool onDrawPath(const DrawPathArgs&) override;
 
-    std::unique_ptr<GrSmallPathAtlasMgr> fAtlasMgr;
-
     typedef GrPathRenderer INHERITED;
 };