ccpr: Recycle the stashed atlas's texture explicitly

This solution is more future-proof.

Bug: skia:
Change-Id: Ifa437a511336282d73befddea2656f3fcdb3f2ef
Reviewed-on: https://skia-review.googlesource.com/136964
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp
index 4eeddea..b336e8c 100644
--- a/src/gpu/ccpr/GrCCAtlas.cpp
+++ b/src/gpu/ccpr/GrCCAtlas.cpp
@@ -77,12 +77,15 @@
                     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);
+                    if (!fBackingTexture) {
+                        GrSurfaceDesc desc;
+                        desc.fFlags = kRenderTarget_GrSurfaceFlag;
+                        desc.fWidth = fWidth;
+                        desc.fHeight = fHeight;
+                        desc.fConfig = pixelConfig;
+                        fBackingTexture = resourceProvider->createTexture(desc, SkBudgeted::kYes);
+                    }
+                    return fBackingTexture;
             },
             GrProxyProvider::Renderable::kYes, kTextureOrigin, pixelConfig, caps);
 }
@@ -165,13 +168,20 @@
 }
 
 sk_sp<GrRenderTargetContext> GrCCAtlas::makeRenderTargetContext(
-        GrOnFlushResourceProvider* onFlushRP) {
+        GrOnFlushResourceProvider* onFlushRP, sk_sp<GrTexture> backingTexture) {
     SkASSERT(!fTextureProxy->priv().isInstantiated());  // This method should only be called once.
     // 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);
     SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
 
+    if (backingTexture) {
+        SkASSERT(backingTexture->config() == kAlpha_half_GrPixelConfig);
+        SkASSERT(backingTexture->width() == fWidth);
+        SkASSERT(backingTexture->height() == fHeight);
+        fBackingTexture = std::move(backingTexture);
+    }
+
     sk_sp<GrRenderTargetContext> rtc =
             onFlushRP->makeRenderTargetContext(fTextureProxy, nullptr, nullptr);
     if (!rtc) {
diff --git a/src/gpu/ccpr/GrCCAtlas.h b/src/gpu/ccpr/GrCCAtlas.h
index 76d2a98..1a7ba1f 100644
--- a/src/gpu/ccpr/GrCCAtlas.h
+++ b/src/gpu/ccpr/GrCCAtlas.h
@@ -11,8 +11,7 @@
 #include "GrAllocator.h"
 #include "GrNonAtomicRef.h"
 #include "GrResourceKey.h"
-#include "GrTypes.h"
-#include "GrTypesPriv.h"
+#include "GrTexture.h"
 #include "SkRefCnt.h"
 #include "SkSize.h"
 
@@ -50,6 +49,8 @@
     ~GrCCAtlas();
 
     GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
+    int currentWidth() const { return fWidth; }
+    int currentHeight() const { return fHeight; }
 
     // 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.
@@ -80,7 +81,12 @@
     // 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*);
+    //
+    // 'backingTexture', if provided, is a renderable texture with which to instantiate our proxy.
+    // If null then we will create a texture using the resource provider. The purpose of this param
+    // is to provide a guaranteed way to recycle a stashed atlas texture from a previous flush.
+    sk_sp<GrRenderTargetContext> makeRenderTargetContext(GrOnFlushResourceProvider*,
+                                                         sk_sp<GrTexture> backingTexture = nullptr);
 
 private:
     class Node;
@@ -100,6 +106,7 @@
 
     sk_sp<CachedAtlasInfo> fCachedAtlasInfo;
     sk_sp<GrTextureProxy> fTextureProxy;
+    sk_sp<GrTexture> fBackingTexture;
 };
 
 /**
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index a1cecb3..362ae77 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -279,13 +279,18 @@
         baseCopyInstance = endCopyInstance;
     }
 
-    // Release the stashed atlas before creating new one(s). This allows us to recycle the same
-    // underlying texture with the upcoming rendered atlases.
-    stashedAtlasProxy = nullptr;
-
     // Render the coverage count atlas(es).
     for (GrCCAtlasStack::Iter atlas(fRenderedAtlasStack); atlas.next();) {
-        if (auto rtc = atlas->makeRenderTargetContext(onFlushRP)) {
+        // Copies will be finished by the time we get to this atlas. See if we can recycle the
+        // stashed atlas texture instead of creating a new one.
+        sk_sp<GrTexture> backingTexture;
+        if (stashedAtlasProxy && atlas->currentWidth() == stashedAtlasProxy->width() &&
+            atlas->currentHeight() == stashedAtlasProxy->height()) {
+            backingTexture = sk_ref_sp(stashedAtlasProxy->priv().peekTexture());
+            stashedAtlasProxy = nullptr;
+        }
+
+        if (auto rtc = atlas->makeRenderTargetContext(onFlushRP, std::move(backingTexture))) {
             auto op = RenderAtlasOp::Make(rtc->surfPriv().getContext(), sk_ref_sp(this),
                                           atlas->getUserBatchID(), atlas->drawBounds());
             rtc->addDrawOp(GrNoClip(), std::move(op));