Add option to skip intermediate release/fulfill calls for promise images.

SkiaRenderer does not delete promise image textures when they are released
but not done. Refulfilling promise image textures takes a significant amount
of CPU time. This allows us to fulfill each promise image once.

Bug: skia:8736
Change-Id: I7ad7fa9678ed0ec4bb714b71fbf920ab4a845409
Reviewed-on: https://skia-review.googlesource.com/c/188039
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index 7c731cf..e4aabb7 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -360,7 +360,8 @@
         PromiseImageTextureFulfillProc fulfillProc,
         PromiseImageTextureReleaseProc releaseProc,
         PromiseImageTextureDoneProc doneProc,
-        PromiseImageTextureContext textureContext) {
+        PromiseImageTextureContext textureContext,
+        DelayReleaseCallback delayReleaseCallback) {
     SkASSERT(context);
     SkASSERT(width > 0 && height > 0);
     SkASSERT(doneProc);
@@ -402,9 +403,11 @@
                                        PromiseImageTextureReleaseProc releaseProc,
                                        PromiseImageTextureDoneProc doneProc,
                                        PromiseImageTextureContext context,
+                                       DelayReleaseCallback delayReleaseCallback,
                                        GrPixelConfig config)
                 : fFulfillProc(fulfillProc)
-                , fConfig(config) {
+                , fConfig(config)
+                , fDelayReleaseCallback(delayReleaseCallback) {
             auto doneHelper = sk_make_sp<GrReleaseProcHelper>(doneProc, context);
             fReleaseContext = sk_make_sp<IdleContext::PromiseImageReleaseContext>(
                     releaseProc, context, std::move(doneHelper));
@@ -414,8 +417,14 @@
 
         sk_sp<GrSurface> operator()(GrResourceProvider* resourceProvider) {
             if (!resourceProvider) {
+                if (fDelayedReleaseTexture) {
+                    fDelayedReleaseTexture.reset();
+                }
                 return nullptr;
             }
+            if (fDelayedReleaseTexture) {
+                return fDelayedReleaseTexture;
+            }
 
             sk_sp<GrTexture> cachedTexture;
             SkASSERT(fLastFulfilledKey.isValid() == (fLastFulfillID > 0));
@@ -459,6 +468,7 @@
                 return sk_sp<GrTexture>();
             }
 
+            sk_sp<GrTexture> tex;
             static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
             GrUniqueKey::Builder builder(&fLastFulfilledKey, kDomain, 2, "promise");
             builder[0] = promiseTexture->uniqueID();
@@ -467,7 +477,6 @@
             // A texture with this key may already exist from a different instance of this lazy
             // callback. This could happen if the client fulfills a promise image with a texture
             // that was previously used to fulfill a different promise image.
-            sk_sp<GrTexture> tex;
             if (auto surf = resourceProvider->findByUniqueKey<GrSurface>(fLastFulfilledKey)) {
                 tex = sk_ref_sp(surf->asTexture());
                 SkASSERT(tex);
@@ -484,6 +493,9 @@
                 }
             }
             this->addToIdleContext(tex.get());
+            if (fDelayReleaseCallback == DelayReleaseCallback::kYes) {
+                fDelayedReleaseTexture = tex;
+            }
             tex->resourcePriv().setUniqueKey(fLastFulfilledKey);
             SkASSERT(fContextID == SK_InvalidUniqueID ||
                      fContextID == tex->getContext()->uniqueID());
@@ -567,15 +579,17 @@
         }
 
         sk_sp<IdleContext::PromiseImageReleaseContext> fReleaseContext;
+        sk_sp<GrTexture> fDelayedReleaseTexture;
         PromiseImageTextureFulfillProc fFulfillProc;
         GrPixelConfig fConfig;
+        DelayReleaseCallback fDelayReleaseCallback;
 
         // ID of the last SkPromiseImageTexture given to us by the client.
         uint32_t fLastFulfillID = 0;
         // ID of the GrContext that we are interacting with.
         uint32_t fContextID = SK_InvalidUniqueID;
         GrUniqueKey fLastFulfilledKey;
-    } callback(fulfillProc, releaseProc, doneProc, textureContext, config);
+    } callback(fulfillProc, releaseProc, doneProc, textureContext, delayReleaseCallback, config);
 
     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();