Reland "Reintroduce deinstantiate lazy proxy types and use for promise images."

This is a reland of 8b40ac35b2ec31a61c751e610b891681df272283

Original change's description:
> Reintroduce deinstantiate lazy proxy types and use for promise images.
> 
> This reverts a fraction of b2c5dae65df952999f0a12b9df80bc1433ffa19a to
> restore the deinstantiate lazy proxy type, supporting implementation,
> and tests.
> 
> Use them for promise images to avoid thread safety issues for promise
> image resources. Makes promise image instantiation callbacks do a thread
> safe unref of their fulfilled GrTexture in GrResourceCache. The
> GrResourceCache mechanism for receiving unref messages is extended to
> allow multiple pending unrefs. All this is new.
> 
> 
> Bug: skia:8800
> Change-Id: I7b1d4fea13c053b6fbbd39c0c6eaf567b8bf81f1
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/199002
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Reviewed-by: Robert Phillips <robertphillips@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

Bug: skia:8800
Change-Id: Ib939fc5c19edf0c6b965c9f6adf0afedd4267703
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/201220
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index ec2e651..908be47 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -445,12 +445,23 @@
 
         ~PromiseLazyInstantiateCallback() {
             if (fIdleCallback) {
+                SkASSERT(!fTexture);
                 // We were never fulfilled. Pass false so done proc is still called.
                 fIdleCallback->abandon();
             }
+            // Our destructor can run on any thread. We trigger the unref of fTexture by message.
+            if (fTexture) {
+                SkASSERT(!fIdleCallback);
+                SkMessageBus<GrGpuResourceFreedMessage>::Post({fTexture, fTextureContextID});
+            }
         }
 
         sk_sp<GrSurface> operator()(GrResourceProvider* resourceProvider) {
+            // Our proxy is getting instantiated for the second+ time. We are only allowed to call
+            // Fulfill once. So return our cached result.
+            if (fTexture) {
+                return sk_ref_sp(fTexture);
+            }
             SkASSERT(fIdleCallback);
             PromiseImageTextureContext textureContext = fIdleCallback->context();
             sk_sp<SkPromiseImageTexture> promiseTexture = fFulfillProc(textureContext);
@@ -495,10 +506,20 @@
             }
             tex->addIdleProc(std::move(fIdleCallback));
             promiseTexture->addKeyToInvalidate(tex->getContext()->priv().contextID(), key);
+            fTexture = tex.get();
+            // We need to hold on to the GrTexture in case our proxy gets reinstantiated. However,
+            // we can't unref in our destructor because we may be on another thread then. So we
+            // let the cache know it is waiting on an unref message. We will send that message from
+            // our destructor.
+            GrContext* context = fTexture->getContext();
+            context->priv().getResourceCache()->insertDelayedResourceUnref(fTexture);
+            fTextureContextID = context->priv().contextID();
             return std::move(tex);
         }
 
     private:
+        GrTexture* fTexture = nullptr;
+        uint32_t fTextureContextID = SK_InvalidUniqueID;
         sk_sp<GrRefCntedCallback> fIdleCallback;
         PromiseImageTextureFulfillProc fFulfillProc;
         GrPixelConfig fConfig;
@@ -515,5 +536,5 @@
     return proxyProvider->createLazyProxy(std::move(callback), backendFormat, desc, origin,
                                           mipMapped, GrInternalSurfaceFlags::kReadOnly,
                                           SkBackingFit::kExact, SkBudgeted::kNo,
-                                          GrSurfaceProxy::LazyInstantiationType::kSingleUse);
+                                          GrSurfaceProxy::LazyInstantiationType::kDeinstantiate);
 }