Avoid unbounded listener growth on SkImage_Lazy when textures are purged

Generalizes the system used on SkPathRef where a GrTexture's key
destructor signals that a listener on the image can be removed via
the unique key custom data.

Removes texturesAreCacheable() from SkImageGenerator. This was used to
prevent unbounded growth in a narrow situation related to
GrBackendTextureImageGenerator.


Change-Id: I3c605da099acfac94751e793331e356a0979d359
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/274038
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index edea530..ece4e5a 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -5,6 +5,8 @@
  * found in the LICENSE file.
  */
 
+#include "src/gpu/GrSoftwarePathRenderer.h"
+
 #include "include/private/SkSemaphore.h"
 #include "src/core/SkTaskGroup.h"
 #include "src/core/SkTraceEvent.h"
@@ -19,8 +21,8 @@
 #include "src/gpu/GrRecordingContextPriv.h"
 #include "src/gpu/GrRenderTargetContextPriv.h"
 #include "src/gpu/GrSWMaskHelper.h"
-#include "src/gpu/GrSoftwarePathRenderer.h"
 #include "src/gpu/GrSurfaceContextPriv.h"
+#include "src/gpu/SkGr.h"
 #include "src/gpu/geometry/GrShape.h"
 #include "src/gpu/ops/GrDrawOp.h"
 
@@ -215,20 +217,6 @@
     GrAA fAA;
 };
 
-// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
-class PathInvalidator : public SkPathRef::GenIDChangeListener {
-public:
-    PathInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID)
-            : fMsg(key, contextUniqueID) {}
-
-private:
-    GrUniqueKeyInvalidatedMessage fMsg;
-
-    void onChange() override {
-        SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
-    }
-};
-
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -379,25 +367,11 @@
             SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
 
             // We will add an invalidator to the path so that if the path goes away we will
-            // delete or recycle the mask texture. We also invalidate the other way: If the mask
-            // goes away we signal that the invalidator on the path can be removed. This prevents
-            // unbounded growth of invalidators on long lived paths.
-            auto invalidator =
-                    sk_make_sp<PathInvalidator>(maskKey, args.fContext->priv().contextID());
-
-            auto invalidateInvalidator = [](const void* ptr, void* /*context*/) {
-                auto invalidator = reinterpret_cast<const sk_sp<PathInvalidator>*>(ptr);
-                (*invalidator)->markShouldUnregisterFromPath();
-                delete invalidator;
-            };
-            auto data = SkData::MakeWithProc(new sk_sp<PathInvalidator>(invalidator),
-                                             sizeof(sk_sp<PathInvalidator>),
-                                             invalidateInvalidator,
-                                             nullptr);
-            maskKey.setCustomData(std::move(data));
+            // delete or recycle the mask texture.
+            auto listener = GrMakeUniqueKeyInvalidationListener(&maskKey,
+                                                                args.fContext->priv().contextID());
             fProxyProvider->assignUniqueKeyToProxy(maskKey, view.asTextureProxy());
-
-            args.fShape->addGenIDChangeListener(std::move(invalidator));
+            args.fShape->addGenIDChangeListener(std::move(listener));
         }
     }
     SkASSERT(view);