Make non-ddl lazy proxys clean-up and delete their callbacks immediately after instanstation.

This makes sure resources are released and free'd as soon as possible if we
no longer need them.

Bug: skia:
Change-Id: Ic216987649c54183f8cbbff90a633860a97754b3
Reviewed-on: https://skia-review.googlesource.com/105721
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/include/private/GrRenderTargetProxy.h b/include/private/GrRenderTargetProxy.h
index b0018a7..1672fd9 100644
--- a/include/private/GrRenderTargetProxy.h
+++ b/include/private/GrRenderTargetProxy.h
@@ -77,8 +77,8 @@
     //
     // The minimal knowledge version is used for CCPR where we are generating an atlas but we do not
     // know the final size until flush time.
-    GrRenderTargetProxy(LazyInstantiateCallback&&, const GrSurfaceDesc&, SkBackingFit, SkBudgeted,
-                        uint32_t flags);
+    GrRenderTargetProxy(LazyInstantiateCallback&&, LazyInstantiationType lazyType,
+                        const GrSurfaceDesc&, SkBackingFit, SkBudgeted, uint32_t flags);
 
     // Wrapped version
     GrRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index 84353ee..6bfb700 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -182,6 +182,11 @@
 
 class GrSurfaceProxy : public GrIORefProxy {
 public:
+    enum class LazyInstantiationType {
+        kSingleUse,    // Instantiation callback is allowed to be called only once
+        kMultipleUse,  // Instantiation callback can be called multiple times.
+    };
+
     enum class LazyState {
         kNot,       // The proxy is instantiated or does not have a lazy callback
         kPartially, // The proxy has a lazy callback but knows basic information about itself.
@@ -351,7 +356,8 @@
 protected:
     // Deferred version
     GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
-            : GrSurfaceProxy(nullptr, desc, fit, budgeted, flags) {
+            : GrSurfaceProxy(nullptr, LazyInstantiationType::kSingleUse,
+                             desc, fit, budgeted, flags) {
         // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
     }
 
@@ -359,8 +365,9 @@
                                                                    GrSurfaceOrigin* outOrigin)>;
 
     // Lazy-callback version
-    GrSurfaceProxy(LazyInstantiateCallback&& callback, const GrSurfaceDesc& desc,
-                   SkBackingFit fit, SkBudgeted budgeted, uint32_t flags);
+    GrSurfaceProxy(LazyInstantiateCallback&& callback, LazyInstantiationType lazyType,
+                   const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted,
+                   uint32_t flags);
 
     // Wrapped version
     GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin, SkBackingFit fit);
@@ -408,6 +415,12 @@
     const UniqueID       fUniqueID; // set from the backing resource for wrapped resources
 
     LazyInstantiateCallback fLazyInstantiateCallback;
+    // If this is set to kSingleuse, then after one call to fLazyInstantiateCallback we will cleanup
+    // the lazy callback and then delete it. This will allow for any refs and resources being held
+    // by the standard function to be released. This is specifically useful in non-dll cases where
+    // we make lazy proxies and instantiate them immediately.
+    // Note: This is ignored if fLazyInstantiateCallback is null.
+    LazyInstantiationType fLazyInstantiationType;
     SkDEBUGCODE(virtual void validateLazySurface(const GrSurface*) = 0;)
 
     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index 3aee3de..3adfa58 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -80,8 +80,8 @@
     //
     // The minimal knowledge version is used for CCPR where we are generating an atlas but we do not
     // know the final size until flush time.
-    GrTextureProxy(LazyInstantiateCallback&&, const GrSurfaceDesc& desc, GrMipMapped,
-                   SkBackingFit fit, SkBudgeted budgeted, uint32_t flags);
+    GrTextureProxy(LazyInstantiateCallback&&, LazyInstantiationType, const GrSurfaceDesc& desc,
+                   GrMipMapped, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags);
 
     // Wrapped version
     GrTextureProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index 0076a1a..dd2a1b7 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -537,11 +537,17 @@
     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
              (desc.fWidth > 0 && desc.fHeight > 0));
     uint32_t flags = GrResourceProvider::kNoPendingIO_Flag;
+
+    using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
+    // For non-ddl draws always make lazy proxy's single use.
+    LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse
+                                                       : LazyInstantiationType::kMultipleUse;
+
     return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ?
-                                 new GrTextureRenderTargetProxy(std::move(callback), desc,
+                                 new GrTextureRenderTargetProxy(std::move(callback), lazyType, desc,
                                                                 mipMapped, fit, budgeted, flags) :
-                                 new GrTextureProxy(std::move(callback), desc, mipMapped, fit,
-                                                    budgeted, flags));
+                                 new GrTextureProxy(std::move(callback), lazyType, desc, mipMapped,
+                                                    fit, budgeted, flags));
 }
 
 sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy(
@@ -553,13 +559,19 @@
     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
              (desc.fWidth > 0 && desc.fHeight > 0));
     uint32_t flags = GrResourceProvider::kNoPendingIO_Flag;
+
+    using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
+    // For non-ddl draws always make lazy proxy's single use.
+    LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse
+                                                       : LazyInstantiationType::kMultipleUse;
+
     if (Textureable::kYes == textureable) {
-        return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(std::move(callback), desc,
-                                                                         mipMapped, fit, budgeted,
-                                                                         flags));
+        return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(std::move(callback),
+                                                                         lazyType, desc, mipMapped,
+                                                                         fit, budgeted, flags));
     }
 
-    return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(callback), desc,
+    return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(callback), lazyType, desc,
                                                               fit, budgeted, flags));
 }
 
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index af661c1..0147485 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -156,7 +156,6 @@
 
     using LazyInstantiateCallback = std::function<sk_sp<GrSurface>(GrResourceProvider*,
                                                                    GrSurfaceOrigin* outOrigin)>;
-
     enum class Textureable : bool {
         kNo = false,
         kYes = true
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index 59dcd73..914ade5 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -36,10 +36,11 @@
 
 // Lazy-callback version
 GrRenderTargetProxy::GrRenderTargetProxy(LazyInstantiateCallback&& callback,
+                                         LazyInstantiationType lazyType,
                                          const GrSurfaceDesc& desc,
                                          SkBackingFit fit, SkBudgeted budgeted,
                                          uint32_t flags)
-        : INHERITED(std::move(callback), desc, fit, budgeted, flags)
+        : INHERITED(std::move(callback), lazyType, desc, fit, budgeted, flags)
         , fSampleCnt(desc.fSampleCnt)
         , fNeedsStencil(false)
         , fRenderTargetFlags(GrRenderTargetFlags::kNone) {
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index c9cf535..5026d0e 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -44,8 +44,9 @@
 #endif
 
 // Lazy-callback version
-GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, const GrSurfaceDesc& desc,
-                               SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
+GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, LazyInstantiationType lazyType,
+                               const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted,
+                               uint32_t flags)
         : fConfig(desc.fConfig)
         , fWidth(desc.fWidth)
         , fHeight(desc.fHeight)
@@ -54,6 +55,7 @@
         , fBudgeted(budgeted)
         , fFlags(flags)
         , fLazyInstantiateCallback(std::move(callback))
+        , fLazyInstantiationType(lazyType)
         , fNeedsClear(SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag))
         , fGpuMemorySize(kInvalidGpuMemorySize)
         , fLastOpList(nullptr) {
@@ -63,7 +65,6 @@
     } else {
         SkASSERT(is_valid_non_lazy(desc));
     }
-
 }
 
 // Wrapped version
@@ -361,6 +362,10 @@
     }
 
     sk_sp<GrSurface> surface = fProxy->fLazyInstantiateCallback(resourceProvider, outOrigin);
+    if (GrSurfaceProxy::LazyInstantiationType::kSingleUse == fProxy->fLazyInstantiationType) {
+        fProxy->fLazyInstantiateCallback(nullptr, nullptr);
+        fProxy->fLazyInstantiateCallback = nullptr;
+    }
     if (!surface) {
         fProxy->fWidth = 0;
         fProxy->fHeight = 0;
diff --git a/src/gpu/GrSurfaceProxyPriv.h b/src/gpu/GrSurfaceProxyPriv.h
index 2de820d..e5d1f90 100644
--- a/src/gpu/GrSurfaceProxyPriv.h
+++ b/src/gpu/GrSurfaceProxyPriv.h
@@ -70,6 +70,14 @@
 
     bool doLazyInstantiation(GrResourceProvider*);
 
+    GrSurfaceProxy::LazyInstantiationType lazyInstantiationType() const {
+        return fProxy->fLazyInstantiationType;
+    }
+
+    void testingOnly_setLazyInstantiationType(GrSurfaceProxy::LazyInstantiationType lazyType) {
+        fProxy->fLazyInstantiationType = lazyType;
+    }
+
     static bool AttachStencilIfNeeded(GrResourceProvider*, GrSurface*, bool needsStencil);
 
 private:
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 3362ec8..72b8106 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -26,10 +26,10 @@
 }
 
 // Lazy-callback version
-GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback, const GrSurfaceDesc& desc,
-                               GrMipMapped mipMapped, SkBackingFit fit, SkBudgeted budgeted,
-                               uint32_t flags)
-        : INHERITED(std::move(callback), desc, fit, budgeted, flags)
+GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback, LazyInstantiationType lazyType,
+                               const GrSurfaceDesc& desc, GrMipMapped mipMapped, SkBackingFit fit,
+                               SkBudgeted budgeted, uint32_t flags)
+        : INHERITED(std::move(callback), lazyType, desc, fit, budgeted, flags)
         , fMipMapped(mipMapped)
         , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy)
         , fProxyProvider(nullptr)
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index 3312077..b4889fa 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -29,16 +29,17 @@
 
 // Lazy-callback version
 GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(LazyInstantiateCallback&& callback,
+                                                       LazyInstantiationType lazyType,
                                                        const GrSurfaceDesc& desc,
                                                        GrMipMapped mipMapped,
                                                        SkBackingFit fit,
                                                        SkBudgeted budgeted,
                                                        uint32_t flags)
-        : GrSurfaceProxy(std::move(callback), desc, fit, budgeted, flags)
+        : GrSurfaceProxy(std::move(callback), lazyType, desc, fit, budgeted, flags)
         // Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null
         // callbacks to the texture and RT proxies simply to route to the appropriate constructors.
-        , GrTextureProxy(LazyInstantiateCallback(), desc, mipMapped, fit, budgeted, flags)
-        , GrRenderTargetProxy(LazyInstantiateCallback(), desc, fit, budgeted, flags) {
+        , GrTextureProxy(LazyInstantiateCallback(), lazyType, desc, mipMapped, fit, budgeted, flags)
+        , GrRenderTargetProxy(LazyInstantiateCallback(), lazyType, desc, fit, budgeted, flags) {
 }
 
 // Wrapped version
diff --git a/src/gpu/GrTextureRenderTargetProxy.h b/src/gpu/GrTextureRenderTargetProxy.h
index 2947dd4..178185d 100644
--- a/src/gpu/GrTextureRenderTargetProxy.h
+++ b/src/gpu/GrTextureRenderTargetProxy.h
@@ -32,8 +32,9 @@
                                SkBackingFit, SkBudgeted, uint32_t flags);
 
     // Lazy-callback version
-    GrTextureRenderTargetProxy(LazyInstantiateCallback&&, const GrSurfaceDesc& desc, GrMipMapped,
-                               SkBackingFit, SkBudgeted, uint32_t flags);
+    GrTextureRenderTargetProxy(LazyInstantiateCallback&&, LazyInstantiationType,
+                               const GrSurfaceDesc& desc, GrMipMapped, SkBackingFit, SkBudgeted,
+                               uint32_t flags);
 
     // Wrapped version
     GrTextureRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp
index 1994eeb..5a0211d 100644
--- a/tests/LazyProxyTest.cpp
+++ b/tests/LazyProxyTest.cpp
@@ -213,29 +213,42 @@
     desc.fHeight = kSize;
     desc.fConfig = kRGBA_8888_GrPixelConfig;
 
+    using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
     for (bool doInstantiate : {true, false}) {
-        int testCount = 0;
-        int* testCountPtr = &testCount;
-        sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
-                [testCountPtr](GrResourceProvider* resourceProvider, GrSurfaceOrigin* outOrigin) {
-                    if (!resourceProvider) {
-                        *testCountPtr = -1;
+        for (auto lazyType : {LazyInstantiationType::kSingleUse,
+                              LazyInstantiationType::kMultipleUse}) {
+            int testCount = 0;
+            int* testCountPtr = &testCount;
+            sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
+                    [testCountPtr](GrResourceProvider* resourceProvider,
+                                   GrSurfaceOrigin* /*outOrigin*/) {
+                        if (!resourceProvider) {
+                            *testCountPtr = -1;
+                            return sk_sp<GrTexture>();
+                        }
+                        *testCountPtr = 1;
                         return sk_sp<GrTexture>();
-                    }
-                    *testCountPtr = 1;
-                    return sk_sp<GrTexture>();
-                }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
+                    }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
 
-        REPORTER_ASSERT(reporter, 0 == testCount);
+            proxy->priv().testingOnly_setLazyInstantiationType(lazyType);
 
-        if (doInstantiate) {
-            proxy->priv().doLazyInstantiation(ctx->contextPriv().resourceProvider());
-            REPORTER_ASSERT(reporter, 1 == testCount);
-            proxy.reset();
-            REPORTER_ASSERT(reporter, -1 == testCount);
-        } else {
-            proxy.reset();
-            REPORTER_ASSERT(reporter, -1 == testCount);
+            REPORTER_ASSERT(reporter, 0 == testCount);
+
+            if (doInstantiate) {
+                proxy->priv().doLazyInstantiation(ctx->contextPriv().resourceProvider());
+                if (LazyInstantiationType::kSingleUse == proxy->priv().lazyInstantiationType()) {
+                    // In SingleUse we will call the cleanup and delete the callback in the
+                    // doLazyInstantiationCall.
+                    REPORTER_ASSERT(reporter, -1 == testCount);
+                } else {
+                    REPORTER_ASSERT(reporter, 1 == testCount);
+                }
+                proxy.reset();
+                REPORTER_ASSERT(reporter, -1 == testCount);
+            } else {
+                proxy.reset();
+                REPORTER_ASSERT(reporter, -1 == testCount);
+            }
         }
     }
 }