Make lazy proxies have 2 modes for proxy/surface key management.

kSynced: Proxy and GrSurface key kept in sync.

kUnsynced: Proxy and GrSurface keys are unrelated.

This will allow cross-context image generators' lazy instantiation
callbacks to use unique keys to find any pre-existing backing GrTexture
rather than keeping an unref'ed bare pointer to the GrTexture.

Bug: skia:8927

Change-Id: Id15e2a64e8d2e56c4ce70b9399eb1d8bcea6ac9a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/204723
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index be1f17c..72a09f1 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -12,7 +12,7 @@
 #include "GrBackendSurface.h"
 #include "GrGpuResource.h"
 #include "GrSurface.h"
-
+#include "GrTexture.h"
 #include "SkRect.h"
 
 class GrCaps;
@@ -205,6 +205,45 @@
 
 class GrSurfaceProxy : public GrIORefProxy {
 public:
+    /**
+     * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return.
+     * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls
+     * the key relationship between proxies and their targets.
+     */
+    enum class LazyInstantiationKeyMode {
+        /**
+         * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to
+         * return a GrSurface that already has a unique key unrelated to the proxy's key.
+         */
+        kUnsynced,
+        /**
+         * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface
+         * returned from the lazy instantiation callback must not have a unique key or have the same
+         * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned
+         * to the GrSurface.
+         */
+        kSynced
+    };
+
+    struct LazyInstantiationResult {
+        LazyInstantiationResult() = default;
+        LazyInstantiationResult(const LazyInstantiationResult&) = default;
+        LazyInstantiationResult(LazyInstantiationResult&& that) = default;
+        LazyInstantiationResult(sk_sp<GrSurface> surf,
+                                LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced)
+                : fSurface(std::move(surf)), fKeyMode(mode) {}
+        LazyInstantiationResult(sk_sp<GrTexture> tex)
+                : LazyInstantiationResult(sk_sp<GrSurface>(std::move(tex))) {}
+
+        LazyInstantiationResult& operator=(const LazyInstantiationResult&) = default;
+        LazyInstantiationResult& operator=(LazyInstantiationResult&&) = default;
+
+        sk_sp<GrSurface> fSurface;
+        LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced;
+    };
+
+    using LazyInstantiateCallback = std::function<LazyInstantiationResult(GrResourceProvider*)>;
+
     enum class LazyInstantiationType {
         kSingleUse,      // Instantiation callback is allowed to be called only once.
         kMultipleUse,    // Instantiation callback can be called multiple times.
@@ -431,8 +470,6 @@
         // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
     }
 
-    using LazyInstantiateCallback = std::function<sk_sp<GrSurface>(GrResourceProvider*)>;
-
     // Lazy-callback version
     GrSurfaceProxy(LazyInstantiateCallback&&, LazyInstantiationType,
                    const GrBackendFormat& format, const GrSurfaceDesc&, GrSurfaceOrigin,
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index 0d890f5..6851cde 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -57,7 +57,7 @@
      */
     const GrUniqueKey& getUniqueKey() const {
 #ifdef SK_DEBUG
-        if (fTarget && fUniqueKey.isValid()) {
+        if (fTarget && fUniqueKey.isValid() && fSyncTargetKey) {
             SkASSERT(fTarget->getUniqueKey().isValid());
             // It is possible for a non-keyed proxy to have a uniquely keyed resource assigned to
             // it. This just means that a future user of the resource will be filling it with unique
@@ -83,9 +83,10 @@
 
 protected:
     // DDL TODO: rm the GrSurfaceProxy friending
-    friend class GrSurfaceProxy; // for ctors
-    friend class GrProxyProvider; // for ctors
+    friend class GrSurfaceProxy;   // for ctors
+    friend class GrProxyProvider;  // for ctors
     friend class GrTextureProxyPriv;
+    friend class GrSurfaceProxyPriv;  // ability to change key sync state after lazy instantiation.
 
     // Deferred version - when constructed with data the origin is always kTopLeft.
     GrTextureProxy(const GrBackendFormat&, const GrSurfaceDesc& srcDesc, GrMipMapped, SkBackingFit,
@@ -116,6 +117,8 @@
 
     sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
 
+    void setTargetKeySync(bool sync) { fSyncTargetKey = sync; }
+
 private:
     // WARNING: Be careful when adding or removing fields here. ASAN is likely to trigger warnings
     // when instantiating GrTextureRenderTargetProxy. The std::function in GrSurfaceProxy makes
@@ -126,6 +129,7 @@
     // address of other types, leading to this problem.
 
     GrMipMapped      fMipMapped;
+    bool             fSyncTargetKey = true;  // Should target's unique key be sync'ed with ours.
 
     GrUniqueKey      fUniqueKey;
     GrProxyProvider* fProxyProvider; // only set when fUniqueKey is valid
diff --git a/src/core/SkDeferredDisplayListRecorder.cpp b/src/core/SkDeferredDisplayListRecorder.cpp
index e81dbba..6bf3390 100644
--- a/src/core/SkDeferredDisplayListRecorder.cpp
+++ b/src/core/SkDeferredDisplayListRecorder.cpp
@@ -162,14 +162,11 @@
 
     sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
             [lazyProxyData](GrResourceProvider* resourceProvider) {
-                if (!resourceProvider) {
-                    return sk_sp<GrSurface>();
-                }
-
                 // The proxy backing the destination surface had better have been instantiated
                 // prior to the proxy backing the DLL's surface. Steal its GrRenderTarget.
                 SkASSERT(lazyProxyData->fReplayDest->peekSurface());
-                return sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
+                auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
+                return GrSurfaceProxy::LazyInstantiationResult(std::move(surface));
             },
             format,
             desc,
diff --git a/src/gpu/GrAHardwareBufferImageGenerator.cpp b/src/gpu/GrAHardwareBufferImageGenerator.cpp
index 2055955..51908e1 100644
--- a/src/gpu/GrAHardwareBufferImageGenerator.cpp
+++ b/src/gpu/GrAHardwareBufferImageGenerator.cpp
@@ -150,7 +150,8 @@
 
     sk_sp<GrTextureProxy> texProxy = proxyProvider->createLazyProxy(
             [direct, buffer = AutoAHBRelease(hardwareBuffer), width, height, pixelConfig,
-             isProtectedContent, backendFormat](GrResourceProvider* resourceProvider) {
+             isProtectedContent, backendFormat](GrResourceProvider* resourceProvider)
+                    -> GrSurfaceProxy::LazyInstantiationResult {
                 GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
                 GrAHardwareBufferUtils::DeleteImageCtx deleteImageCtx = nullptr;
 
@@ -163,7 +164,7 @@
                                                                    backendFormat,
                                                                    false);
                 if (!backendTex.isValid()) {
-                    return sk_sp<GrTexture>();
+                    return {};
                 }
                 SkASSERT(deleteImageProc && deleteImageCtx);
 
@@ -175,14 +176,14 @@
                         backendTex, kBorrow_GrWrapOwnership, GrWrapCacheable::kYes, kRead_GrIOType);
                 if (!tex) {
                     deleteImageProc(deleteImageCtx);
-                    return sk_sp<GrTexture>();
+                    return {};
                 }
 
                 if (deleteImageProc) {
                     tex->setRelease(deleteImageProc, deleteImageCtx);
                 }
 
-                return tex;
+                return std::move(tex);
             },
             backendFormat, desc, fSurfaceOrigin, GrMipMapped::kNo,
             GrInternalSurfaceFlags::kReadOnly, SkBackingFit::kExact, SkBudgeted::kNo);
diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp
index 1bba019..8fdf8cd 100644
--- a/src/gpu/GrBackendTextureImageGenerator.cpp
+++ b/src/gpu/GrBackendTextureImageGenerator.cpp
@@ -136,18 +136,15 @@
     desc.fConfig = fConfig;
     GrMipMapped mipMapped = fBackendTexture.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo;
 
-    // Must make copies of member variables to capture in the lambda since this image generator may
-    // be deleted before we actuallly execute the lambda.
-    sk_sp<GrSemaphore> semaphore = fSemaphore;
-    GrBackendTexture backendTexture = fBackendTexture;
-    RefHelper* refHelper = fRefHelper;
-
-    GrBackendFormat format = backendTexture.getBackendFormat();
+    GrBackendFormat format = fBackendTexture.getBackendFormat();
     SkASSERT(format.isValid());
 
+    // Must make copies of member variables to capture in the lambda since this image generator may
+    // be deleted before we actually execute the lambda.
     sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
-            [refHelper, releaseProcHelper, semaphore,
-             backendTexture](GrResourceProvider* resourceProvider) {
+            [refHelper = fRefHelper, releaseProcHelper, semaphore = fSemaphore,
+             backendTexture = fBackendTexture](GrResourceProvider* resourceProvider)
+                    -> GrSurfaceProxy::LazyInstantiationResult {
                 if (semaphore) {
                     resourceProvider->priv().gpu()->waitSemaphore(semaphore);
                 }
@@ -172,14 +169,13 @@
                             backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
                             kRead_GrIOType);
                     if (!tex) {
-                        return sk_sp<GrTexture>();
+                        return {};
                     }
                     refHelper->fBorrowedTexture = tex.get();
 
                     tex->setRelease(releaseProcHelper);
                 }
-
-                return tex;
+                return std::move(tex);
             },
             format, desc, fSurfaceOrigin, mipMapped, GrInternalSurfaceFlags::kReadOnly,
             SkBackingFit::kExact, SkBudgeted::kNo);
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index efa7bf0..526e99c 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -255,8 +255,8 @@
                 if (surfaceFlags & GrInternalSurfaceFlags::kNoPendingIO) {
                     resourceProviderFlags |= GrResourceProvider::Flags::kNoPendingIO;
                 }
-                return resourceProvider->createTexture(desc, budgeted, fit, mipLevel,
-                                                       resourceProviderFlags);
+                return LazyInstantiationResult(resourceProvider->createTexture(
+                        desc, budgeted, fit, mipLevel, resourceProviderFlags));
             },
             format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, surfaceFlags, fit, budgeted);
 
@@ -374,8 +374,8 @@
                     SkASSERT(texels[i].fPixels);
                 }
 
-                return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(),
-                                                       mipLevelCount);
+                return LazyInstantiationResult(resourceProvider->createTexture(
+                        desc, SkBudgeted::kYes, texels.get(), mipLevelCount));
             },
             format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes, SkBackingFit::kExact,
             SkBudgeted::kYes);
@@ -446,7 +446,8 @@
             GrMipLevel texels;
             texels.fPixels = data->data();
             texels.fRowBytes = GrBytesPerPixel(desc.fConfig)*desc.fWidth;
-            return resourceProvider->createTexture(desc, SkBudgeted::kYes, &texels, 1);
+            return LazyInstantiationResult(
+                    resourceProvider->createTexture(desc, SkBudgeted::kYes, &texels, 1));
         },
         format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
         SkBudgeted::kYes);
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index 358cf1d..089093c 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -136,7 +136,9 @@
     sk_sp<GrRenderTargetProxy> wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo&,
                                                                    const GrVkDrawableInfo&);
 
-    using LazyInstantiateCallback = std::function<sk_sp<GrSurface>(GrResourceProvider*)>;
+    using LazyInstantiationKeyMode = GrSurfaceProxy::LazyInstantiationKeyMode;
+    using LazyInstantiationResult = GrSurfaceProxy::LazyInstantiationResult;
+    using LazyInstantiateCallback = GrSurfaceProxy::LazyInstantiateCallback;
 
     enum class Renderable : bool {
         kNo = false,
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index b5ddb6e..e9f14cb 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -433,8 +433,11 @@
                                                         fProxy->asTextureProxy()->getUniqueKey());
     }
 
+    bool syncKey = true;
     if (!surface) {
-        surface = fProxy->fLazyInstantiateCallback(resourceProvider);
+        auto result = fProxy->fLazyInstantiateCallback(resourceProvider);
+        surface = std::move(result.fSurface);
+        syncKey = result.fKeyMode == GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
     }
     if (GrSurfaceProxy::LazyInstantiationType::kSingleUse == fProxy->fLazyInstantiationType) {
         fProxy->fLazyInstantiateCallback = nullptr;
@@ -463,14 +466,19 @@
     }
 
     if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) {
-        const GrUniqueKey& key = texProxy->getUniqueKey();
-        if (key.isValid()) {
-            if (!surface->asTexture()->getUniqueKey().isValid()) {
-                // If 'surface' is newly created, attach the unique key
-                resourceProvider->assignUniqueKeyToResource(key, surface.get());
+        texProxy->setTargetKeySync(syncKey);
+        if (syncKey) {
+            const GrUniqueKey& key = texProxy->getUniqueKey();
+            if (key.isValid()) {
+                if (!surface->asTexture()->getUniqueKey().isValid()) {
+                    // If 'surface' is newly created, attach the unique key
+                    resourceProvider->assignUniqueKeyToResource(key, surface.get());
+                } else {
+                    // otherwise we had better have reattached to a cached version
+                    SkASSERT(surface->asTexture()->getUniqueKey() == key);
+                }
             } else {
-                // otherwise we had better have reattached to a cached version
-                SkASSERT(surface->asTexture()->getUniqueKey() == key);
+                SkASSERT(!surface->getUniqueKey().isValid());
             }
         }
     }
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 362c469..b319dba 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -154,7 +154,7 @@
     SkASSERT(key.isValid());
     SkASSERT(!fUniqueKey.isValid()); // proxies can only ever get one uniqueKey
 
-    if (fTarget) {
+    if (fTarget && fSyncTargetKey) {
         if (!fTarget->getUniqueKey().isValid()) {
             fTarget->resourcePriv().setUniqueKey(key);
         }
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp
index c297443..82b06f0 100644
--- a/src/gpu/ccpr/GrCCAtlas.cpp
+++ b/src/gpu/ccpr/GrCCAtlas.cpp
@@ -85,9 +85,6 @@
 
     fTextureProxy = GrProxyProvider::MakeFullyLazyProxy(
             [this, pixelConfig](GrResourceProvider* resourceProvider) {
-                    if (!resourceProvider) {
-                        return sk_sp<GrTexture>();
-                    }
                     if (!fBackingTexture) {
                         GrSurfaceDesc desc;
                         desc.fFlags = kRenderTarget_GrSurfaceFlag;
@@ -96,7 +93,7 @@
                         desc.fConfig = pixelConfig;
                         fBackingTexture = resourceProvider->createTexture(desc, SkBudgeted::kYes);
                     }
-                    return fBackingTexture;
+                    return GrSurfaceProxy::LazyInstantiationResult(fBackingTexture);
             },
             format, GrProxyProvider::Renderable::kYes, kTextureOrigin, pixelConfig, caps);
 }
diff --git a/src/gpu/ccpr/GrCCClipPath.cpp b/src/gpu/ccpr/GrCCClipPath.cpp
index 8b8d8a6..4c82fb1 100644
--- a/src/gpu/ccpr/GrCCClipPath.cpp
+++ b/src/gpu/ccpr/GrCCClipPath.cpp
@@ -20,10 +20,8 @@
                                                                         GrSRGBEncoded::kNo);
 
     fAtlasLazyProxy = GrProxyProvider::MakeFullyLazyProxy(
-            [this](GrResourceProvider* resourceProvider) {
-                if (!resourceProvider) {
-                    return sk_sp<GrTexture>();
-                }
+            [this](GrResourceProvider* resourceProvider)
+                    -> GrSurfaceProxy::LazyInstantiationResult {
                 SkASSERT(fHasAtlas);
                 SkASSERT(!fHasAtlasTransform);
 
@@ -31,7 +29,7 @@
                 if (!textureProxy || !textureProxy->instantiate(resourceProvider)) {
                     fAtlasScale = fAtlasTranslate = {0, 0};
                     SkDEBUGCODE(fHasAtlasTransform = true);
-                    return sk_sp<GrTexture>();
+                    return {};
                 }
 
                 SkASSERT(kTopLeft_GrSurfaceOrigin == textureProxy->origin());
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index 12c4b54..3d53e8d 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -453,11 +453,16 @@
             }
         }
 
-        sk_sp<GrSurface> operator()(GrResourceProvider* resourceProvider) {
+        GrSurfaceProxy::LazyInstantiationResult operator()(GrResourceProvider* resourceProvider) {
+            // We use the unique key in a way that is unrelated to the SkImage-based key that the
+            // proxy may receive, hence kUnsynced.
+            static constexpr auto kKeySyncMode =
+                    GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
+
             // 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);
+                return {sk_ref_sp(fTexture), kKeySyncMode};
             }
             SkASSERT(fDoneCallback);
             PromiseImageTextureContext textureContext = fDoneCallback->context();
@@ -466,13 +471,13 @@
             // the return from fulfill was invalid or we fail for some other reason.
             auto releaseCallback = sk_make_sp<GrRefCntedCallback>(fReleaseProc, textureContext);
             if (!promiseTexture) {
-                return sk_sp<GrTexture>();
+                return {};
             }
 
             auto backendTexture = promiseTexture->backendTexture();
             backendTexture.fConfig = fConfig;
             if (!backendTexture.isValid()) {
-                return sk_sp<GrTexture>();
+                return {};
             }
 
             sk_sp<GrTexture> tex;
@@ -494,7 +499,7 @@
                              kRead_GrIOType))) {
                     tex->resourcePriv().setUniqueKey(key);
                 } else {
-                    return sk_sp<GrTexture>();
+                    return {};
                 }
             }
             auto releaseIdleState = fVersion == PromiseImageApiVersion::kLegacy
@@ -511,7 +516,7 @@
             GrContext* context = fTexture->getContext();
             context->priv().getResourceCache()->insertDelayedResourceUnref(fTexture);
             fTextureContextID = context->priv().contextID();
-            return std::move(tex);
+            return {std::move(tex), kKeySyncMode};
         }
 
     private:
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index b46ea1e..7c0d3a8 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -445,7 +445,11 @@
                 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
                 auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
                 auto singleUseLazyCB = [&texture](GrResourceProvider* rp) {
-                    return std::move(texture);
+                    auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
+                    if (texture->getUniqueKey().isValid()) {
+                        mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
+                    }
+                    return GrSurfaceProxy::LazyInstantiationResult{std::move(texture), mode};
                 };
                 GrSurfaceDesc desc;
                 desc.fWidth = w;
@@ -490,7 +494,12 @@
 
                 // Make a proxy that should deinstantiate even if we keep a ref on it.
                 auto deinstantiateLazyCB = [&make, &context](GrResourceProvider* rp) {
-                    return make(context, 3);
+                    auto texture = make(context, 3);
+                    auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
+                    if (texture->getUniqueKey().isValid()) {
+                        mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
+                    }
+                    return GrSurfaceProxy::LazyInstantiationResult{std::move(texture), mode};
                 };
                 proxy = context->priv().proxyProvider()->createLazyProxy(
                         deinstantiateLazyCB, backendFormat, desc,
diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp
index beb66ad..d50177a 100644
--- a/tests/LazyProxyTest.cpp
+++ b/tests/LazyProxyTest.cpp
@@ -84,14 +84,12 @@
             const GrBackendFormat format =
                     ctx->priv().caps()->getBackendFormatFromColorType(kRGB_565_SkColorType);
             fProxy = GrProxyProvider::MakeFullyLazyProxy(
-                    [this, nullTexture](GrResourceProvider* rp) {
-                        if (!rp) {
-                            return sk_sp<GrTexture>();
-                        }
+                    [this, nullTexture](
+                            GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
                         fTest->fHasOpTexture = true;
                         if (nullTexture) {
-                            return sk_sp<GrTexture>();
+                            return {};
                         } else {
                             GrSurfaceDesc desc;
                             desc.fWidth = 1234;
@@ -99,7 +97,7 @@
                             desc.fConfig = kRGB_565_GrPixelConfig;
                             sk_sp<GrTexture> texture = rp->createTexture(desc, SkBudgeted::kYes);
                             REPORTER_ASSERT(fTest->fReporter, texture);
-                            return texture;
+                            return std::move(texture);
                         }
                     },
                     format, GrProxyProvider::Renderable::kNo, kTopLeft_GrSurfaceOrigin,
@@ -134,19 +132,14 @@
                 ctx->priv().caps()->getBackendFormatFromGrColorType(GrColorType::kAlpha_F16,
                                                                     GrSRGBEncoded::kNo);
             fLazyProxy = GrProxyProvider::MakeFullyLazyProxy(
-                                [this](GrResourceProvider* rp) {
-                                    if (!rp) {
-                                        return sk_sp<GrTexture>();
-                                    }
-                                    REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
-                                    fTest->fHasClipTexture = true;
-                                    fAtlas->instantiate(rp);
-                                    return sk_ref_sp(fAtlas->peekTexture());
-                                },
-                                format,
-                                GrProxyProvider::Renderable::kYes,
-                                kBottomLeft_GrSurfaceOrigin,
-                                kAlpha_half_GrPixelConfig, *proxyProvider->caps());
+                    [this](GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
+                        REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
+                        fTest->fHasClipTexture = true;
+                        fAtlas->instantiate(rp);
+                        return sk_ref_sp(fAtlas->peekTexture());
+                    },
+                    format, GrProxyProvider::Renderable::kYes, kBottomLeft_GrSurfaceOrigin,
+                    kAlpha_half_GrPixelConfig, *proxyProvider->caps());
             fAccess.reset(fLazyProxy, GrSamplerState::Filter::kNearest,
                           GrSamplerState::WrapMode::kClamp);
             this->setTextureSamplerCnt(1);
@@ -248,6 +241,7 @@
             ctx->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
 
     using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
+    using LazyInstantiationResult = GrSurfaceProxy::LazyInstantiationResult;
     for (bool doInstantiate : {true, false}) {
         for (auto lazyType : {LazyInstantiationType::kSingleUse,
                               LazyInstantiationType::kMultipleUse,
@@ -268,7 +262,7 @@
                 }
                 TestCallback& operator=(const TestCallback& that) = delete;
 
-                sk_sp<GrSurface> operator()(GrResourceProvider* resourceProvider) const {
+                LazyInstantiationResult operator()(GrResourceProvider* resourceProvider) const {
                     *fValue = 1;
                     return {};
                 }
@@ -337,15 +331,16 @@
                 ctx->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
 
         fLazyProxy = proxyProvider->createLazyProxy(
-                [testExecuteValue, shouldFailInstantiation, desc](GrResourceProvider* rp) {
+                [testExecuteValue, shouldFailInstantiation,
+                 desc](GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
                     if (shouldFailInstantiation) {
                         *testExecuteValue = 1;
-                        return sk_sp<GrTexture>();
+                        return {};
                     }
                     return rp->createTexture(desc, SkBudgeted::kNo);
                 },
-                format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
-                SkBackingFit::kExact, SkBudgeted::kNo);
+                format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
+                SkBudgeted::kNo);
 
         SkASSERT(fLazyProxy.get());
 
@@ -479,16 +474,17 @@
                 nullptr, kSize, kSize, GrColorType::kRGBA_8888, false, GrMipMapped::kNo);
 
         sk_sp<GrTextureProxy> lazyProxy = proxyProvider->createLazyProxy(
-                [instantiatePtr, releasePtr, backendTex](GrResourceProvider* rp) {
+                [instantiatePtr, releasePtr,
+                 backendTex](GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
                     sk_sp<GrTexture> texture =
                             rp->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership,
                                                    GrWrapCacheable::kNo, kRead_GrIOType);
                     if (!texture) {
-                        return sk_sp<GrTexture>();
+                        return {};
                     }
                     (*instantiatePtr)++;
                     texture->setRelease(DeinstantiateReleaseProc, releasePtr);
-                    return texture;
+                    return std::move(texture);
                 },
                 format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
                 GrInternalSurfaceFlags::kReadOnly, SkBackingFit::kExact, SkBudgeted::kNo, lazyType);
diff --git a/tests/OnFlushCallbackTest.cpp b/tests/OnFlushCallbackTest.cpp
index 4f974408..96d227b 100644
--- a/tests/OnFlushCallbackTest.cpp
+++ b/tests/OnFlushCallbackTest.cpp
@@ -304,11 +304,8 @@
         const GrBackendFormat format = caps->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
 
         fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
-                [](GrResourceProvider* resourceProvider) {
-                    if (!resourceProvider) {
-                        return sk_sp<GrTexture>();
-                    }
-
+                [](GrResourceProvider* resourceProvider)
+                        -> GrSurfaceProxy::LazyInstantiationResult {
                     GrSurfaceDesc desc;
                     desc.fFlags = kRenderTarget_GrSurfaceFlag;
                     // TODO: until partial flushes in MDB lands we're stuck having
@@ -317,8 +314,9 @@
                     desc.fHeight = kAtlasTileSize;
                     desc.fConfig = kRGBA_8888_GrPixelConfig;
 
-                    return resourceProvider->createTexture(desc, SkBudgeted::kYes,
-                                                           GrResourceProvider::Flags::kNoPendingIO);
+                    auto texture = resourceProvider->createTexture(
+                            desc, SkBudgeted::kYes, GrResourceProvider::Flags::kNoPendingIO);
+                    return std::move(texture);
                 },
                 format,
                 GrProxyProvider::Renderable::kYes,
diff --git a/tests/ResourceAllocatorTest.cpp b/tests/ResourceAllocatorTest.cpp
index 0a1a19a..e968a51 100644
--- a/tests/ResourceAllocatorTest.cpp
+++ b/tests/ResourceAllocatorTest.cpp
@@ -312,15 +312,14 @@
     desc.fSampleCnt = p.fSampleCnt;
 
     SkBackingFit fit = p.fFit;
-    auto callback = [fit, desc](GrResourceProvider* resourceProvider) -> sk_sp<GrSurface> {
-        if (!resourceProvider) {
-            return nullptr;
-        }
+    auto callback = [fit, desc](GrResourceProvider* resourceProvider) {
+        sk_sp<GrTexture> texture;
         if (fit == SkBackingFit::kApprox) {
-            return resourceProvider->createApproxTexture(desc, GrResourceProvider::Flags::kNone);
+            texture = resourceProvider->createApproxTexture(desc, GrResourceProvider::Flags::kNone);
         } else {
-            return resourceProvider->createTexture(desc, SkBudgeted::kNo);
+            texture = resourceProvider->createTexture(desc, SkBudgeted::kNo);
         }
+        return GrSurfaceProxy::LazyInstantiationResult(std::move(texture));
     };
     const GrBackendFormat format = caps->getBackendFormatFromColorType(p.fColorType);
     auto lazyType = deinstantiate ? GrSurfaceProxy::LazyInstantiationType ::kDeinstantiate