Revert "Revert changes to unbreak bots."

This reverts commit 49721c84376bcb91daff84bcaa0225298866ee60.

Reason for revert: fixed double usage of plane release context in
 YUVUtils.

Original change's description:
> Revert changes to unbreak bots.
>
> f01a9d90209d824ea7449b06ad7c5e35349d6d17
> is the culprit
>
>
> Revert "GrRefCntedCallback has Make function."
>
> This reverts commit b2c42140ea10d1781917023a84465386f92d2a06.
>
> Revert "Add SkImage::MakeFromYUVATexturesCopyToExternal"
>
> This reverts commit f01a9d90209d824ea7449b06ad7c5e35349d6d17.
>
> Bug: skia:10632
> Change-Id: Ief076f168b63ff8ca15b607163a13d5f52a733d2
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/331798
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

TBR=bsalomon@google.com

Change-Id: I41cdfe0d5b8587f85fae0c804c059c0d6ff92800


Bug: skia:10632
Change-Id: I41cdfe0d5b8587f85fae0c804c059c0d6ff92800
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/331876
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index d8a98e8..a3d8c8f 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -27,7 +27,11 @@
     which wraps an SkYUVAInfo and compatible set of GrBackendTextures. The provides
     a more complete and structured specification of the planar configuration. Previous
     version is deprecated.
+    Already deprecated MakeFromYUVATexturesCopyToExternal added to replace other deprecated
+    APIs. It's not recommended that clients use this and instead use the pattern described
+    in the API comment.
     https://review.skia.org/317762
+    https://review.skia.org/329956
 
   * Add field to GrContextOptions to disable mipmap support even if the backend
     supports it.
diff --git a/gm/wacky_yuv_formats.cpp b/gm/wacky_yuv_formats.cpp
index afdc4cf..400378c 100644
--- a/gm/wacky_yuv_formats.cpp
+++ b/gm/wacky_yuv_formats.cpp
@@ -752,6 +752,9 @@
             case Type::kFromGenerator:
                 name += "_imggen";
                 break;
+            case Type::kFromTexturesCopyToExternal:
+                name += "_fromtextureswithcopy";
+                break;
         }
 
         return name;
@@ -943,6 +946,9 @@
 DEF_GM(return new WackyYUVFormatsGM(/* target cs */ false,
                                     /* subset */ false,
                                     WackyYUVFormatsGM::Type::kFromPixmaps);)
+DEF_GM(return new WackyYUVFormatsGM(/* target cs */ false,
+                                    /* subset */ false,
+                                    WackyYUVFormatsGM::Type::kFromTexturesCopyToExternal);)
 
 class YUVMakeColorSpaceGM : public GpuGM {
 public:
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index d0c58bf..26cb86e 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -428,6 +428,46 @@
                                                TextureReleaseProc textureReleaseProc = nullptr,
                                                ReleaseContext releaseContext = nullptr);
 
+    /** Deprecated.
+        Creates an SkImage from YUV[A] planar textures by copying them to another caller-provided
+        texture and retaining that result texture in the SkImage. This should be preferred over
+        MakeFromYUVTexturesCopyWithExternalBackend and MakeFromNV12TexturesCopyWithExternalBackend.
+        However, this is deprecated and instead clients should make a SkSurface from
+        'rgbaResultTexture` using SkSurface::MakeFromBackendTexture, make an image from the planes
+        using MakeFromYUVATextures, and finally draw the image to the surface.
+
+        Note that the draw that converts to RGBA is not issued to the underlying API until a flush/
+        submit occurs so the YUVA textures are not safe to delete or overwrite until yuvaReleaseProc
+        is called.
+
+        The dimensions of the result RGBA texture must match the dimensions of the YUVA planar data.
+
+        @param context            GPU context
+        @param yuvaTextures       A set of textures containing YUVA data and a description of the
+                                  data and transformation to RGBA.
+        @param rgbaResultTexture  The renderable texture that will hold the result of the conversion
+                                  to RGBA and be retained in the resulting SkImage.
+        @param colorType          colorType of the result as stored in rgbaResultTexture. Must be
+                                  compatible with the texture's format.
+        @param imageColorSpace    range of colors of the resulting image after conversion to RGB;
+                                  may be nullptr
+        @param yuvaReleaseProc    called when the backend textures in 'yuvaTextures' can be released
+        @param yuvaReleaseContext state passed to yuvaReleaseProc
+        @param rgbaReleaseProc    called when the 'rgbaResultTexture' can be released
+        @param rgbaReleaseContext state passed to rgbaReleaseProc
+        @return                   created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromYUVATexturesCopyToExternal(
+            GrRecordingContext* context,
+            const GrYUVABackendTextures& yuvaTextures,
+            const GrBackendTexture& rgbaResultTexture,
+            SkColorType colorType,
+            sk_sp<SkColorSpace> imageColorSpace = nullptr,
+            TextureReleaseProc yuvaReleaseProc = nullptr,
+            ReleaseContext yuvaReleaseContext = nullptr,
+            TextureReleaseProc rgbaReleaseProc = nullptr,
+            ReleaseContext rgbaReleaseContext = nullptr);
+
     /**
         Deprecated. Use version that takes GrYUVABackendTextures.
 
diff --git a/include/core/SkYUVAPixmaps.h b/include/core/SkYUVAPixmaps.h
index 69e1085..bdaa66b 100644
--- a/include/core/SkYUVAPixmaps.h
+++ b/include/core/SkYUVAPixmaps.h
@@ -171,8 +171,11 @@
  */
 class SK_API SkYUVAPixmaps {
 public:
+    using DataType = SkYUVAPixmapInfo::DataType;
     static constexpr auto kMaxPlanes = SkYUVAPixmapInfo::kMaxPlanes;
 
+    static SkColorType RecommendedRGBAColorType(DataType);
+
     /** Allocate space for pixmaps' pixels in the SkYUVAPixmaps. */
     static SkYUVAPixmaps Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo);
 
@@ -217,6 +220,8 @@
 
     const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; }
 
+    DataType dataType() const { return fDataType; }
+
     SkYUVAPixmapInfo pixmapsInfo() const;
 
     /** Number of pixmap planes or 0 if this SkYUVAPixmaps is invalid. */
@@ -250,11 +255,12 @@
 
 private:
     SkYUVAPixmaps(const SkYUVAPixmapInfo&, sk_sp<SkData>);
-    SkYUVAPixmaps(const SkYUVAInfo&, const SkPixmap[kMaxPlanes]);
+    SkYUVAPixmaps(const SkYUVAInfo&, DataType, const SkPixmap[kMaxPlanes]);
 
-    SkYUVAInfo fYUVAInfo;
     std::array<SkPixmap, kMaxPlanes> fPlanes = {};
     sk_sp<SkData> fData;
+    SkYUVAInfo fYUVAInfo;
+    DataType fDataType;
 };
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 053b586..e6f599e 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -1205,19 +1205,29 @@
 /**
  * Ref-counted object that calls a callback from its destructor.
  */
-class GrRefCntedCallback : public SkRefCnt {
+class GrRefCntedCallback : public SkNVRefCnt<GrRefCntedCallback> {
 public:
     using Context = void*;
     using Callback = void (*)(Context);
 
-    GrRefCntedCallback(Callback proc, Context ctx) : fReleaseProc(proc), fReleaseCtx(ctx) {
-        SkASSERT(proc);
+    static sk_sp<GrRefCntedCallback> Make(Callback proc, Context ctx) {
+        if (!proc) {
+            return nullptr;
+        }
+        return sk_sp<GrRefCntedCallback>(new GrRefCntedCallback(proc, ctx));
     }
-    ~GrRefCntedCallback() override { fReleaseProc ? fReleaseProc(fReleaseCtx) : void(); }
+
+    ~GrRefCntedCallback() { fReleaseProc(fReleaseCtx); }
 
     Context context() const { return fReleaseCtx; }
 
 private:
+    GrRefCntedCallback(Callback proc, Context ctx) : fReleaseProc(proc), fReleaseCtx(ctx) {}
+    GrRefCntedCallback(const GrRefCntedCallback&) = delete;
+    GrRefCntedCallback(GrRefCntedCallback&&) = delete;
+    GrRefCntedCallback& operator=(const GrRefCntedCallback&) = delete;
+    GrRefCntedCallback& operator=(GrRefCntedCallback&&) = delete;
+
     Callback fReleaseProc;
     Context fReleaseCtx;
 };
diff --git a/src/core/SkYUVAPixmaps.cpp b/src/core/SkYUVAPixmaps.cpp
index 2ce4ba5..36d1562 100644
--- a/src/core/SkYUVAPixmaps.cpp
+++ b/src/core/SkYUVAPixmaps.cpp
@@ -177,6 +177,18 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+SkColorType SkYUVAPixmaps::RecommendedRGBAColorType(DataType dataType) {
+    switch (dataType) {
+        case DataType::kUnorm8:         return kRGBA_8888_SkColorType;
+        // F16 has better GPU support than 16 bit unorm. Often "16" bit unorm values are actually
+        // lower precision.
+        case DataType::kUnorm16:        return kRGBA_F16_SkColorType;
+        case DataType::kFloat16:        return kRGBA_F16_SkColorType;
+        case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType;
+    }
+    SkUNREACHABLE;
+}
+
 SkYUVAPixmaps SkYUVAPixmaps::Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo) {
     if (!yuvaPixmapInfo.isValid()) {
         return {};
@@ -223,7 +235,7 @@
     }
     SkPixmap pixmaps[kMaxPlanes];
     yuvaPixmapInfo.initPixmapsFromSingleAllocation(memory, pixmaps);
-    return SkYUVAPixmaps(yuvaPixmapInfo.yuvaInfo(), pixmaps);
+    return SkYUVAPixmaps(yuvaPixmapInfo.yuvaInfo(), yuvaPixmapInfo.dataType(), pixmaps);
 }
 
 SkYUVAPixmaps SkYUVAPixmaps::FromExternalPixmaps(const SkYUVAInfo& yuvaInfo,
@@ -235,23 +247,27 @@
         colorTypes[i] = pixmaps[i].colorType();
         rowBytes[i] = pixmaps[i].rowBytes();
     }
-    if (!SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes).isValid()) {
+    SkYUVAPixmapInfo yuvaPixmapInfo(yuvaInfo, colorTypes, rowBytes);
+    if (!yuvaPixmapInfo.isValid()) {
         return {};
     }
-    return SkYUVAPixmaps(yuvaInfo, pixmaps);
+    return SkYUVAPixmaps(yuvaInfo, yuvaPixmapInfo.dataType(), pixmaps);
 }
 
 SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data)
-        : fYUVAInfo(yuvaPixmapInfo.yuvaInfo())
-        , fData(std::move(data)) {
+        : fData(std::move(data))
+        , fYUVAInfo(yuvaPixmapInfo.yuvaInfo())
+        , fDataType(yuvaPixmapInfo.dataType()) {
     SkASSERT(yuvaPixmapInfo.isValid());
     SkASSERT(yuvaPixmapInfo.computeTotalBytes() <= fData->size());
     SkAssertResult(yuvaPixmapInfo.initPixmapsFromSingleAllocation(fData->writable_data(),
                                                                   fPlanes.data()));
 }
 
-SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAInfo& yuvaInfo, const SkPixmap pixmaps[kMaxPlanes])
-        : fYUVAInfo(yuvaInfo) {
+SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAInfo& yuvaInfo,
+                             DataType dataType,
+                             const SkPixmap pixmaps[kMaxPlanes])
+        : fYUVAInfo(yuvaInfo), fDataType(dataType) {
     std::copy_n(pixmaps, yuvaInfo.numPlanes(), fPlanes.data());
 }
 
diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp
index 771bb9e..88753e0 100644
--- a/src/gpu/GrBackendTextureImageGenerator.cpp
+++ b/src/gpu/GrBackendTextureImageGenerator.cpp
@@ -127,8 +127,8 @@
         // The ref we add to fRefHelper here will be passed into and owned by the
         // GrRefCntedCallback.
         fRefHelper->ref();
-        releaseProcHelper.reset(
-                new GrRefCntedCallback(ReleaseRefHelper_TextureReleaseProc, fRefHelper));
+        releaseProcHelper =
+                GrRefCntedCallback::Make(ReleaseRefHelper_TextureReleaseProc, fRefHelper);
         fRefHelper->fBorrowingContextReleaseProc = releaseProcHelper.get();
     }
     fRefHelper->fBorrowingContextID = context->priv().contextID();
diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp
index e17b569..b6b6558 100644
--- a/src/gpu/GrDirectContext.cpp
+++ b/src/gpu/GrDirectContext.cpp
@@ -511,10 +511,7 @@
                                                        GrProtected isProtected,
                                                        GrGpuFinishedProc finishedProc,
                                                        GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     if (this->abandoned()) {
@@ -535,10 +532,7 @@
                                                        GrProtected isProtected,
                                                        GrGpuFinishedProc finishedProc,
                                                        GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return {};
@@ -566,10 +560,7 @@
                                                        GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
 
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return {};
@@ -606,10 +597,7 @@
                                            const SkColor4f& color,
                                            GrGpuFinishedProc finishedProc,
                                            GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
@@ -624,10 +612,7 @@
                                            const SkColor4f& color,
                                            GrGpuFinishedProc finishedProc,
                                            GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
@@ -651,10 +636,7 @@
                                            int numLevels,
                                            GrGpuFinishedProc finishedProc,
                                            GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
@@ -711,10 +693,7 @@
                                                              GrGpuFinishedProc finishedProc,
                                                              GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return {};
@@ -749,10 +728,7 @@
                                                              GrGpuFinishedProc finishedProc,
                                                              GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return {};
@@ -781,10 +757,7 @@
                                                      const SkColor4f& color,
                                                      GrGpuFinishedProc finishedProc,
                                                      GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
@@ -799,10 +772,7 @@
                                                      size_t dataSize,
                                                      GrGpuFinishedProc finishedProc,
                                                      GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> finishedCallback;
-    if (finishedProc) {
-        finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
@@ -824,10 +794,7 @@
                                              GrBackendSurfaceMutableState* previousState,
                                              GrGpuFinishedProc finishedProc,
                                              GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> callback;
-    if (finishedProc) {
-        callback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto callback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
@@ -842,10 +809,7 @@
                                                   GrBackendSurfaceMutableState* previousState,
                                                   GrGpuFinishedProc finishedProc,
                                                   GrGpuFinishedContext finishedContext) {
-    sk_sp<GrRefCntedCallback> callback;
-    if (finishedProc) {
-        callback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
-    }
+    auto callback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
     if (this->abandoned()) {
         return false;
diff --git a/src/gpu/GrSurface.h b/src/gpu/GrSurface.h
index 4e6b6da..0e50d6a 100644
--- a/src/gpu/GrSurface.h
+++ b/src/gpu/GrSurface.h
@@ -51,8 +51,7 @@
     typedef void* ReleaseCtx;
     typedef void (*ReleaseProc)(ReleaseCtx);
     void setRelease(ReleaseProc proc, ReleaseCtx ctx) {
-        sk_sp<GrRefCntedCallback> helper(new GrRefCntedCallback(proc, ctx));
-        this->setRelease(std::move(helper));
+        this->setRelease(GrRefCntedCallback::Make(proc, ctx));
     }
 
     /**
diff --git a/src/gpu/GrTexture.h b/src/gpu/GrTexture.h
index ce7ffed..0a3347d 100644
--- a/src/gpu/GrTexture.h
+++ b/src/gpu/GrTexture.h
@@ -64,7 +64,7 @@
     void addIdleProc(GrRefCntedCallback::Callback callback,
                      GrRefCntedCallback::Context context,
                      IdleState state) {
-        this->addIdleProc(sk_make_sp<GrRefCntedCallback>(callback, context), state);
+        this->addIdleProc(GrRefCntedCallback::Make(callback, context), state);
     }
 
     GrTextureType textureType() const { return fTextureType; }
diff --git a/src/gpu/d3d/GrD3DGpu.cpp b/src/gpu/d3d/GrD3DGpu.cpp
index 1dc7078..a9a7c6d 100644
--- a/src/gpu/d3d/GrD3DGpu.cpp
+++ b/src/gpu/d3d/GrD3DGpu.cpp
@@ -213,9 +213,7 @@
 void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
                                GrGpuFinishedContext finishedContext) {
     SkASSERT(finishedProc);
-    sk_sp<GrRefCntedCallback> finishedCallback(
-            new GrRefCntedCallback(finishedProc, finishedContext));
-    this->addFinishedCallback(std::move(finishedCallback));
+    this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext));
 }
 
 void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 4b20c20..3bed568 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -274,9 +274,7 @@
 void GrMtlGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
                                GrGpuFinishedContext finishedContext) {
     SkASSERT(finishedProc);
-    sk_sp<GrRefCntedCallback> finishedCallback(
-            new GrRefCntedCallback(finishedProc, finishedContext));
-    this->addFinishedCallback(std::move(finishedCallback));
+    this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext));
 }
 
 void GrMtlGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 6b397f4..7d22ccd 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -2111,9 +2111,7 @@
 void GrVkGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
                               GrGpuFinishedContext finishedContext) {
     SkASSERT(finishedProc);
-    sk_sp<GrRefCntedCallback> finishedCallback(
-            new GrRefCntedCallback(finishedProc, finishedContext));
-    this->addFinishedCallback(std::move(finishedCallback));
+    this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext));
 }
 
 void GrVkGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index cf56957..20e5ef8 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -5,14 +5,13 @@
  * found in the LICENSE file.
  */
 
-#include <cstddef>
-#include <cstring>
-#include <type_traits>
+#include "src/image/SkImage_Gpu.h"
 
 #include "include/core/SkCanvas.h"
 #include "include/gpu/GrBackendSurface.h"
 #include "include/gpu/GrDirectContext.h"
 #include "include/gpu/GrRecordingContext.h"
+#include "include/gpu/GrYUVABackendTextures.h"
 #include "include/private/SkImageInfoPriv.h"
 #include "src/core/SkAutoPixmapStorage.h"
 #include "src/core/SkBitmapCache.h"
@@ -42,7 +41,10 @@
 #include "src/gpu/GrTextureProxyPriv.h"
 #include "src/gpu/SkGr.h"
 #include "src/gpu/gl/GrGLTexture.h"
-#include "src/image/SkImage_Gpu.h"
+
+#include <cstddef>
+#include <cstring>
+#include <type_traits>
 
 SkImage_Gpu::SkImage_Gpu(sk_sp<GrImageContext> context, uint32_t uniqueID, GrSurfaceProxyView view,
                          SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> colorSpace)
@@ -208,10 +210,7 @@
                                                   sk_sp<SkColorSpace> cs,
                                                   TextureReleaseProc releaseP,
                                                   ReleaseContext releaseC) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (releaseP) {
-        releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(releaseP, releaseC);
 
     if (!rContext) {
         return nullptr;
@@ -242,10 +241,7 @@
                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (releaseP) {
-        releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(releaseP, releaseC);
 
     if (!rContext) {
         return nullptr;
@@ -325,9 +321,11 @@
 sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrRecordingContext* rContext,
                                                      SkYUVColorSpace yuvColorSpace,
                                                      const GrBackendTexture yuvaTextures[],
-                                                     const SkYUVAIndex yuvaIndices[4], SkISize size,
+                                                     const SkYUVAIndex yuvaIndices[4],
+                                                     SkISize size,
                                                      GrSurfaceOrigin origin,
-                                                     GrRenderTargetContext* renderTargetContext) {
+                                                     GrRenderTargetContext* renderTargetContext,
+                                                     sk_sp<GrRefCntedCallback> releaseHelper) {
     SkASSERT(renderTargetContext);
 
     int numTextures;
@@ -337,7 +335,7 @@
 
     GrSurfaceProxyView tempViews[4];
     if (!SkImage_GpuBase::MakeTempTextureProxies(rContext, yuvaTextures, numTextures, yuvaIndices,
-                                                 origin, tempViews, nullptr)) {
+                                                 origin, tempViews, std::move(releaseHelper))) {
         return nullptr;
     }
 
@@ -364,24 +362,13 @@
         SkISize imageSize,
         GrSurfaceOrigin imageOrigin,
         const GrBackendTexture& backendTexture,
+        GrColorType colorType,
         sk_sp<SkColorSpace> imageColorSpace,
-        SkImage::TextureReleaseProc textureReleaseProc,
-        SkImage::ReleaseContext releaseContext) {
+        sk_sp<GrRefCntedCallback> yuvaReleaseHelper,
+        sk_sp<GrRefCntedCallback> rgbaReleaseHelper) {
     const GrCaps* caps = rContext->priv().caps();
-
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (textureReleaseProc) {
-        releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext));
-    }
-
-    GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, kRGBA_8888_SkColorType,
-                                                                backendTexture.getBackendFormat());
-    if (GrColorType::kUnknown == grColorType) {
-        return nullptr;
-    }
-
     SkAlphaType at = SkImage_GpuBase::GetAlphaTypeFromYUVAIndices(yuvaIndices);
-    if (!SkImage_Gpu::ValidateBackendTexture(caps, backendTexture, grColorType,
+    if (!SkImage_Gpu::ValidateBackendTexture(caps, backendTexture, colorType,
                                              kRGBA_8888_SkColorType, at, nullptr)) {
         return nullptr;
     }
@@ -389,14 +376,15 @@
     // Needs to create a render target with external texture
     // in order to draw to it for the yuv->rgb conversion.
     auto renderTargetContext = GrRenderTargetContext::MakeFromBackendTexture(
-            rContext, grColorType, std::move(imageColorSpace), backendTexture, 1, imageOrigin,
-            nullptr, std::move(releaseHelper));
+            rContext, colorType, std::move(imageColorSpace), backendTexture, 1, imageOrigin,
+            nullptr, std::move(rgbaReleaseHelper));
     if (!renderTargetContext) {
         return nullptr;
     }
 
     return SkImage_Gpu::ConvertYUVATexturesToRGB(rContext, yuvColorSpace, yuvaTextures, yuvaIndices,
-                                                 imageSize, imageOrigin, renderTargetContext.get());
+                                                 imageSize, imageOrigin, renderTargetContext.get(),
+                                                 std::move(yuvaReleaseHelper));
 }
 
 // Some YUVA factories infer the YUVAIndices. This helper identifies the channel to use for single
@@ -413,6 +401,42 @@
     }
 }
 
+sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyToExternal(
+        GrRecordingContext* context,
+        const GrYUVABackendTextures& yuvaTextures,
+        const GrBackendTexture& rgbaResultTexture,
+        SkColorType colorType,
+        sk_sp<SkColorSpace> imageColorSpace,
+        TextureReleaseProc yuvaReleaseProc,
+        ReleaseContext yuvaReleaseContext,
+        TextureReleaseProc rgbaReleaseProc,
+        ReleaseContext rgbaReleaseContext) {
+    auto yuvaReleaseHelper = GrRefCntedCallback::Make(yuvaReleaseProc, yuvaReleaseContext);
+    auto rgbaReleaseHelper = GrRefCntedCallback::Make(rgbaReleaseProc, rgbaReleaseContext);
+
+    SkYUVAIndex yuvaIndices[4];
+    int numTextures;
+    if (!yuvaTextures.toYUVAIndices(yuvaIndices) ||
+        !SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
+        return nullptr;
+    }
+    SkASSERT(numTextures == yuvaTextures.numPlanes());
+    if (rgbaResultTexture.dimensions() != yuvaTextures.yuvaInfo().dimensions()) {
+        return nullptr;
+    }
+    return make_flattened_image_with_external_backend(context,
+                                                      yuvaTextures.yuvaInfo().yuvColorSpace(),
+                                                      yuvaTextures.textures().data(),
+                                                      yuvaIndices,
+                                                      rgbaResultTexture.dimensions(),
+                                                      yuvaTextures.textureOrigin(),
+                                                      rgbaResultTexture,
+                                                      SkColorTypeToGrColorType(colorType),
+                                                      std::move(imageColorSpace),
+                                                      std::move(yuvaReleaseHelper),
+                                                      std::move(rgbaReleaseHelper));
+}
+
 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
         GrRecordingContext* ctx, SkYUVColorSpace yuvColorSpace,
         const GrBackendTexture yuvTextures[3], GrSurfaceOrigin imageOrigin,
@@ -422,9 +446,17 @@
             SkYUVAIndex{1, get_single_channel(yuvTextures[1])},
             SkYUVAIndex{2, get_single_channel(yuvTextures[2])},
             SkYUVAIndex{-1, SkColorChannel::kA}};
-    return make_flattened_image_with_external_backend(
-            ctx, yuvColorSpace, yuvTextures, yuvaIndices, yuvTextures[0].dimensions(), imageOrigin,
-            backendTexture, std::move(imageColorSpace), nullptr, nullptr);
+    return make_flattened_image_with_external_backend(ctx,
+                                                      yuvColorSpace,
+                                                      yuvTextures,
+                                                      yuvaIndices,
+                                                      yuvTextures[0].dimensions(),
+                                                      imageOrigin,
+                                                      backendTexture,
+                                                      GrColorType::kRGBA_8888,
+                                                      std::move(imageColorSpace),
+                                                      nullptr,
+                                                      nullptr);
 }
 
 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
@@ -436,15 +468,26 @@
         sk_sp<SkColorSpace> imageColorSpace,
         TextureReleaseProc textureReleaseProc,
         ReleaseContext releaseContext) {
+    auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
+
     SkYUVAIndex yuvaIndices[4] = {
             SkYUVAIndex{0, get_single_channel(nv12Textures[0])},
             SkYUVAIndex{1, SkColorChannel::kR},
             SkYUVAIndex{1, SkColorChannel::kG},
             SkYUVAIndex{-1, SkColorChannel::kA}};
     SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
-    return make_flattened_image_with_external_backend(
-            ctx, yuvColorSpace, nv12Textures, yuvaIndices, size, imageOrigin, backendTexture,
-            std::move(imageColorSpace), textureReleaseProc, releaseContext);
+
+    return make_flattened_image_with_external_backend(ctx,
+                                                      yuvColorSpace,
+                                                      nv12Textures,
+                                                      yuvaIndices,
+                                                      size,
+                                                      imageOrigin,
+                                                      backendTexture,
+                                                      GrColorType::kRGBA_8888,
+                                                      std::move(imageColorSpace),
+                                                      /* plane release helper*/ nullptr,
+                                                      std::move(releaseHelper));
 }
 
 static sk_sp<SkImage> create_image_from_producer(GrRecordingContext* context,
@@ -661,8 +704,7 @@
     }
     SkASSERT(deleteImageProc);
 
-    sk_sp<GrRefCntedCallback> releaseHelper(new GrRefCntedCallback(deleteImageProc,
-                                                                   deleteImageCtx));
+    auto releaseHelper = GrRefCntedCallback::Make(deleteImageProc, deleteImageCtx);
 
     SkColorType colorType =
             GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index 52a7f6e..e3b35e5 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -85,11 +85,15 @@
                                              PromiseImageTextureContext textureContext,
                                              PromiseImageApiVersion);
 
-    static sk_sp<SkImage> ConvertYUVATexturesToRGB(GrRecordingContext*, SkYUVColorSpace,
-                                                   const GrBackendTexture [],
-                                                   const SkYUVAIndex [4],
-                                                   SkISize, GrSurfaceOrigin,
-                                                   GrRenderTargetContext*);
+    static sk_sp<SkImage> ConvertYUVATexturesToRGB(
+            GrRecordingContext*,
+            SkYUVColorSpace,
+            const GrBackendTexture[],
+            const SkYUVAIndex[SkYUVAIndex::kIndexCount],
+            SkISize,
+            GrSurfaceOrigin,
+            GrRenderTargetContext*,
+            sk_sp<GrRefCntedCallback> releaseHelper = nullptr);
 
 private:
     GrSurfaceProxyView fView;
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index c61ccba..3d7cce4 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -380,7 +380,7 @@
                 : fFulfillProc(fulfillProc)
                 , fReleaseProc(releaseProc)
                 , fVersion(version) {
-            fDoneCallback = sk_make_sp<GrRefCntedCallback>(doneProc, context);
+            fDoneCallback = GrRefCntedCallback::Make(doneProc, context);
         }
         PromiseLazyInstantiateCallback(PromiseLazyInstantiateCallback&&) = default;
         PromiseLazyInstantiateCallback(const PromiseLazyInstantiateCallback&) {
@@ -434,7 +434,7 @@
             sk_sp<SkPromiseImageTexture> promiseTexture = fFulfillProc(textureContext);
             // From here on out our contract is that the release proc must be called, even if
             // the return from fulfill was invalid or we fail for some other reason.
-            auto releaseCallback = sk_make_sp<GrRefCntedCallback>(fReleaseProc, textureContext);
+            auto releaseCallback = GrRefCntedCallback::Make(fReleaseProc, textureContext);
             if (!promiseTexture) {
                 fFulfillProcFailed = true;
                 return {};
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index 0135ccb..326d6a2 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -240,10 +240,7 @@
                                              sk_sp<SkColorSpace> imageColorSpace,
                                              TextureReleaseProc textureReleaseProc,
                                              ReleaseContext releaseContext) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (textureReleaseProc) {
-        releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
 
     SkYUVAIndex yuvaIndices[4];
     int numTextures;
@@ -283,10 +280,7 @@
                                              sk_sp<SkColorSpace> imageColorSpace,
                                              TextureReleaseProc textureReleaseProc,
                                              ReleaseContext releaseContext) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (textureReleaseProc) {
-        releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
 
     int numTextures;
     if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 40364a2..1e45d78 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -487,10 +487,7 @@
                                                    const SkSurfaceProps* props,
                                                    SkSurface::TextureReleaseProc textureReleaseProc,
                                                    SkSurface::ReleaseContext releaseContext) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (textureReleaseProc) {
-        releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
 
     if (!context) {
         return nullptr;
@@ -526,10 +523,7 @@
                                             ContentChangeMode mode,
                                             TextureReleaseProc releaseProc,
                                             ReleaseContext releaseContext) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (releaseProc) {
-        releaseHelper.reset(new GrRefCntedCallback(releaseProc, releaseContext));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(releaseProc, releaseContext);
 
     auto context = this->fDevice->recordingContext();
     if (context->abandoned()) {
@@ -604,10 +598,7 @@
                                                         const SkSurfaceProps* props,
                                                         SkSurface::RenderTargetReleaseProc relProc,
                                                         SkSurface::ReleaseContext releaseContext) {
-    sk_sp<GrRefCntedCallback> releaseHelper;
-    if (relProc) {
-        releaseHelper.reset(new GrRefCntedCallback(relProc, releaseContext));
-    }
+    auto releaseHelper = GrRefCntedCallback::Make(relProc, releaseContext);
 
     if (!context) {
         return nullptr;
diff --git a/tools/gpu/ManagedBackendTexture.cpp b/tools/gpu/ManagedBackendTexture.cpp
index a1a7449..593fa16 100644
--- a/tools/gpu/ManagedBackendTexture.cpp
+++ b/tools/gpu/ManagedBackendTexture.cpp
@@ -53,7 +53,7 @@
 }
 
 sk_sp<GrRefCntedCallback> ManagedBackendTexture::refCountedCallback() const {
-    return sk_make_sp<GrRefCntedCallback>(ReleaseProc, this->releaseContext());
+    return GrRefCntedCallback::Make(ReleaseProc, this->releaseContext());
 }
 
 void ManagedBackendTexture::wasAdopted() { fTexture = {}; }
diff --git a/tools/gpu/YUVUtils.cpp b/tools/gpu/YUVUtils.cpp
index 5d42ef7..d6acf75 100644
--- a/tools/gpu/YUVUtils.cpp
+++ b/tools/gpu/YUVUtils.cpp
@@ -221,9 +221,16 @@
             break;
         }
         case Type::kFromTextures:
+        case Type::kFromTexturesCopyToExternal:
             if (!rContext || rContext->abandoned()) {
                 return false;
             }
+            if (fMipmapped == GrMipmapped::kYes) {
+                // If this becomes necessary we should invoke SkMipmapBuilder here to make mip
+                // maps from our src data (and then pass a pixmaps array to initialize the planar
+                // textures.
+                return false;
+            }
             if (auto direct = rContext->asDirectContext()) {
                 sk_sp<sk_gpu_test::ManagedBackendTexture> mbets[SkYUVAInfo::kMaxPlanes];
                 GrBackendTexture textures[SkYUVAInfo::kMaxPlanes];
@@ -242,14 +249,47 @@
                 if (!yuvaTextures.isValid()) {
                     return false;
                 }
-                void* relContext =
-                        sk_gpu_test::ManagedBackendTexture::MakeYUVAReleaseContext(mbets);
-                fYUVImage[idx] = SkImage::MakeFromYUVATextures(
-                        direct,
-                        yuvaTextures,
-                        fColorSpace,
-                        sk_gpu_test::ManagedBackendTexture::ReleaseProc,
-                        relContext);
+                if (type == Type::kFromTextures) {
+                    void* planeRelContext =
+                            sk_gpu_test::ManagedBackendTexture::MakeYUVAReleaseContext(mbets);
+                    fYUVImage[idx] = SkImage::MakeFromYUVATextures(
+                            direct,
+                            yuvaTextures,
+                            fColorSpace,
+                            sk_gpu_test::ManagedBackendTexture::ReleaseProc,
+                            planeRelContext);
+                } else {
+                    SkASSERT(type == Type::kFromTexturesCopyToExternal);
+                    sk_sp<sk_gpu_test::ManagedBackendTexture> rgbaMBET;
+                    for (auto ct : {SkYUVAPixmaps::RecommendedRGBAColorType(fPixmaps.dataType()),
+                                    kRGBA_8888_SkColorType}) {
+                        rgbaMBET = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
+                                direct,
+                                fPixmaps.yuvaInfo().width(),
+                                fPixmaps.yuvaInfo().height(),
+                                kUnknown_SkColorType,
+                                GrMipmapped::kNo,
+                                GrRenderable::kYes);
+                        if (rgbaMBET) {
+                            void* planeRelContext =
+                                    sk_gpu_test::ManagedBackendTexture::MakeYUVAReleaseContext(
+                                            mbets);
+                            fYUVImage[idx] = SkImage::MakeFromYUVATexturesCopyToExternal(
+                                    direct,
+                                    yuvaTextures,
+                                    rgbaMBET->texture(),
+                                    ct,
+                                    fColorSpace,
+                                    sk_gpu_test::ManagedBackendTexture::ReleaseProc,
+                                    planeRelContext,
+                                    sk_gpu_test::ManagedBackendTexture::ReleaseProc,
+                                    rgbaMBET->releaseContext());
+                            if (fYUVImage[idx]) {
+                                break;
+                            }
+                        }
+                    }
+                }
             }
     }
     return fYUVImage[idx] != nullptr;
diff --git a/tools/gpu/YUVUtils.h b/tools/gpu/YUVUtils.h
index e9dad4f..4cc0878 100644
--- a/tools/gpu/YUVUtils.h
+++ b/tools/gpu/YUVUtils.h
@@ -37,6 +37,7 @@
         kFromPixmaps,
         kFromGenerator,
         kFromTextures,
+        kFromTexturesCopyToExternal
     };
 
     SkISize dimensions() const { return fPixmaps.yuvaInfo().dimensions(); }
@@ -52,7 +53,7 @@
     sk_sp<SkColorSpace> fColorSpace;
 
     // Memoized SkImages formed with planes, one for each Type.
-    sk_sp<SkImage> fYUVImage[3];
+    sk_sp<SkImage> fYUVImage[4];
 
     LazyYUVImage() = default;