Add GrBackendTexture/RenderTarget accessors to SkSurface

Change-Id: I63477fd4b8d48dc50af72736f0f8df566cd96d4a
Reviewed-on: https://skia-review.googlesource.com/85220
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Cary Clark <caryclark@skia.org>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/docs/SkSurface_Reference.bmh b/docs/SkSurface_Reference.bmh
index b65d738..e9c5201 100644
--- a/docs/SkSurface_Reference.bmh
+++ b/docs/SkSurface_Reference.bmh
@@ -1089,6 +1089,56 @@
 
 # ------------------------------------------------------------------------------
 
+#Method GrBackendTexture getBackendTexture(BackendHandleAccess backendHandleAccess)
+#In Property
+#Line # returns the GPU reference to texture ##
+Retrieves the backend texture. If Surface has no backend texture, an invalid
+object is returned. Call GrBackendTexture::isValid to determine if the result
+is valid.
+
+The returned GrBackendTexture should be discarded if the Surface is drawn to or deleted.
+
+#Param backendHandleAccess  one of:  kFlushRead_BackendHandleAccess,
+        kFlushWrite_BackendHandleAccess, kDiscardWrite_BackendHandleAccess
+##
+
+#Return GPU texture reference; invalid on failure ##
+
+#NoExample
+##
+
+#SeeAlso GrBackendTexture BackendHandleAccess getBackendRenderTarget
+
+#Method ##
+
+# ------------------------------------------------------------------------------
+
+#Method GrBackendRenderTarget getBackendRenderTarget(BackendHandleAccess backendHandleAccess)
+#In Property
+#Line # returns the GPU reference to render target ##
+
+Retrieves the backend render target. If Surface has no backend render target, an invalid
+object is returned. Call GrBackendRenderTarget::isValid to determine if the result
+is valid.
+
+The returned GrBackendRenderTarget should be discarded if the Surface is drawn to
+or deleted.
+
+#Param backendHandleAccess  one of:  kFlushRead_BackendHandleAccess,
+        kFlushWrite_BackendHandleAccess, kDiscardWrite_BackendHandleAccess
+##
+
+#Return GPU render target reference; invalid on failure ##
+
+#NoExample
+##
+
+#SeeAlso GrBackendRenderTarget BackendHandleAccess getBackendTexture
+
+#Method ##
+
+# ------------------------------------------------------------------------------
+
 #Method SkCanvas* getCanvas()
 #In Property
 #Line # returns Canvas that draws into Surface ##
diff --git a/docs/undocumented.bmh b/docs/undocumented.bmh
index cb5d2af..0b2e296 100644
--- a/docs/undocumented.bmh
+++ b/docs/undocumented.bmh
@@ -713,6 +713,13 @@
 ##
 ##
 
+#Topic RenderTarget
+#Class GrBackendRenderTarget
+    #Method bool isValid() const
+    ##
+##
+##
+
 #Topic Transfer_Mode
 ##
 
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 55a34fc..1950d36 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -20,6 +20,7 @@
 class SkSurfaceCharacterization;
 class GrBackendRenderTarget;
 class GrBackendSemaphore;
+class GrBackendTexture;
 class GrContext;
 class GrRenderTarget;
 
@@ -458,6 +459,35 @@
     bool getRenderTargetHandle(GrBackendObject* backendObject,
                                BackendHandleAccess backendHandleAccess);
 
+#if GR_TEST_UTILS
+    /** Retrieves the backend texture. If Surface has no backend texture, an invalid
+        object is returned. Call GrBackendTexture::isValid to determine if the result
+        is valid.
+
+        The returned GrBackendTexture should be discarded if the Surface is drawn to or deleted.
+
+        @param backendHandleAccess  one of:  kFlushRead_BackendHandleAccess,
+                                             kFlushWrite_BackendHandleAccess,
+                                             kDiscardWrite_BackendHandleAccess
+        @return                     GPU texture reference; invalid on failure
+    */
+    GrBackendTexture getBackendTexture(BackendHandleAccess backendHandleAccess);
+
+    /** Retrieves the backend render target. If Surface has no backend render target, an invalid
+        object is returned. Call GrBackendRenderTarget::isValid to determine if the result
+        is valid.
+
+        The returned GrBackendRenderTarget should be discarded if the Surface is drawn to
+        or deleted.
+
+        @param backendHandleAccess  one of:  kFlushRead_BackendHandleAccess,
+                                             kFlushWrite_BackendHandleAccess,
+                                             kDiscardWrite_BackendHandleAccess
+        @return                     GPU render target reference; invalid on failure
+    */
+    GrBackendRenderTarget getBackendRenderTarget(BackendHandleAccess backendHandleAccess);
+#endif
+
     /** Returns SkCanvas that draws into SkSurface. Subsequent calls return the same SkCanvas.
         SkCanvas returned is managed and owned by SkSurface, and is deleted when SkSurface
         is deleted.
diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h
index 106edb7..8d7886e 100644
--- a/include/gpu/GrBackendSurface.h
+++ b/include/gpu/GrBackendSurface.h
@@ -16,6 +16,24 @@
 #include "vk/GrVkTypes.h"
 #endif
 
+#if !SK_SUPPORT_GPU
+
+// SkSurface and SkImage rely on a minimal version of these always being available
+class SK_API GrBackendTexture {
+public:
+    GrBackendTexture() {}
+
+    bool isValid() const { return false; }
+};
+
+class SK_API GrBackendRenderTarget {
+public:
+    GrBackendRenderTarget() {}
+
+    bool isValid() const { return false; }
+};
+#else
+
 class SK_API GrBackendFormat {
 public:
     // Creates an invalid backend format.
@@ -239,7 +257,11 @@
     // Returns true if the backend texture has been initialized.
     bool isValid() const { return fConfig != kUnknown_GrPixelConfig; }
 
+
+#if GR_TEST_UTILS
     GrPixelConfig testingOnly_getPixelConfig() const;
+    static bool TestingOnly_Equals(const GrBackendRenderTarget&, const GrBackendRenderTarget&);
+#endif
 
 private:
     // Friending for access to the GrPixelConfig
@@ -272,3 +294,5 @@
 
 #endif
 
+#endif
+
diff --git a/include/gpu/gl/GrGLTypes.h b/include/gpu/gl/GrGLTypes.h
index c152e42..442b14d 100644
--- a/include/gpu/gl/GrGLTypes.h
+++ b/include/gpu/gl/GrGLTypes.h
@@ -124,6 +124,10 @@
 struct GrGLFramebufferInfo {
     GrGLuint fFBOID;
     GrGLenum fFormat = 0;
+
+    bool operator==(const GrGLFramebufferInfo& that) const {
+        return fFBOID == that.fFBOID && fFormat == that.fFormat;
+    }
 };
 
 GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrGLFramebufferInfo*));
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 978e66d..97b4d64 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -290,3 +290,40 @@
     }
     return nullptr;
 }
+
+#if GR_TEST_UTILS
+bool GrBackendRenderTarget::TestingOnly_Equals(const GrBackendRenderTarget& r0,
+                                               const GrBackendRenderTarget& r1) {
+    if (!r0.isValid() || !r1.isValid()) {
+        return false; // two invalid backend rendertargets are not considered equal
+    }
+
+    if (r0.fWidth != r1.fWidth ||
+        r0.fHeight != r1.fHeight ||
+        r0.fSampleCnt != r1.fSampleCnt ||
+        r0.fStencilBits != r1.fStencilBits ||
+        r0.fConfig != r1.fConfig ||
+        r0.fBackend != r1.fBackend) {
+        return false;
+    }
+
+    switch (r0.fBackend) {
+    case kOpenGL_GrBackend:
+        return r0.fGLInfo == r1.fGLInfo;
+    case kMock_GrBackend:
+        return r0.fMockInfo == r1.fMockInfo;
+    case kVulkan_GrBackend:
+#ifdef SK_VULKAN
+        return r0.fVkInfo == r1.fVkInfo;
+#else
+        // fall through
+#endif
+    case kMetal_GrBackend: // fall through
+    default:
+        return false;
+    }
+
+    SkASSERT(0);
+    return false;
+}
+#endif
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 6c586c4..fa04d99 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -29,6 +29,7 @@
 #include "GrContext.h"
 #include "SkImage_Gpu.h"
 #endif
+#include "GrBackendSurface.h"
 
 SkImage::SkImage(int width, int height, uint32_t uniqueID)
     : fWidth(width)
@@ -218,6 +219,11 @@
     }
 }
 
+GrBackendTexture SkImage_Base::onGetBackendTexture(bool flushPendingGrContextIO,
+                                                   GrSurfaceOrigin* origin) const {
+    return GrBackendTexture(); // invalid
+}
+
 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
     return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint);
 }
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 950163a..191cf03 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -13,17 +13,9 @@
 #include "SkSurface.h"
 
 #if SK_SUPPORT_GPU
-    #include "GrBackendSurface.h"
     #include "GrTextureProxy.h"
 
     class GrTexture;
-#else
-class SK_API GrBackendTexture {
-public:
-    GrBackendTexture() {}
-
-    bool isValid() const { return false; }
-};
 #endif
 
 #include <new>
@@ -67,13 +59,12 @@
                                                GrSurfaceOrigin* origin) const {
         return 0;
     }
-    virtual GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
-                                                 GrSurfaceOrigin* origin) const {
-        return GrBackendTexture(); // invalid
-    }
 
     virtual GrTexture* onGetTexture() const { return nullptr; }
 #endif
+    virtual GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
+                                                 GrSurfaceOrigin* origin) const;
+
     virtual SkImageCacherator* peekCacherator() const { return nullptr; }
 
     // return a read-only copy of the pixels. We promise to not modify them,
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 9444de7..41bed21 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -6,11 +6,13 @@
  */
 
 #include "SkAtomics.h"
-#include "SkSurface_Base.h"
-#include "SkImagePriv.h"
 #include "SkCanvas.h"
-
 #include "SkFontLCDConfig.h"
+#include "SkImagePriv.h"
+#include "SkSurface_Base.h"
+
+#include "GrBackendSurface.h"
+
 static SkPixelGeometry compute_default_geometry() {
     SkFontLCDConfig::LCDOrder order = SkFontLCDConfig::GetSubpixelOrder();
     if (SkFontLCDConfig::kNONE_LCDOrder == order) {
@@ -70,6 +72,14 @@
     }
 }
 
+GrBackendTexture SkSurface_Base::onGetBackendTexture(BackendHandleAccess) {
+    return GrBackendTexture(); // invalid
+}
+
+GrBackendRenderTarget SkSurface_Base::onGetBackendRenderTarget(BackendHandleAccess) {
+    return GrBackendRenderTarget(); // invalid
+}
+
 void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
     auto image = this->makeImageSnapshot();
     if (image) {
@@ -216,6 +226,16 @@
     return asSB(this)->onGetRenderTargetHandle(obj, access);
 }
 
+#if GR_TEST_UTILS
+GrBackendTexture SkSurface::getBackendTexture(BackendHandleAccess access) {
+    return asSB(this)->onGetBackendTexture(access);
+}
+
+GrBackendRenderTarget SkSurface::getBackendRenderTarget(BackendHandleAccess access) {
+    return asSB(this)->onGetBackendRenderTarget(access);
+}
+#endif
+
 void SkSurface::prepareForExternalIO() {
     this->flush();
 }
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 56a09cf..2771d5f 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -27,6 +27,9 @@
         return false;
     }
 
+    virtual GrBackendTexture onGetBackendTexture(BackendHandleAccess);
+    virtual GrBackendRenderTarget onGetBackendRenderTarget(BackendHandleAccess);
+
     /**
      *  Allocate a canvas that will draw into this surface. We will cache this
      *  canvas, to return the same object to the caller multiple times. We
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index d7a7018..b4a5aee 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -72,6 +72,27 @@
     return true;
 }
 
+GrBackendTexture SkSurface_Gpu::onGetBackendTexture(BackendHandleAccess access) {
+    GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
+    if (!rt) {
+        return GrBackendTexture(); // invalid
+    }
+    GrTexture* texture = rt->asTexture();
+    if (texture) {
+        return texture->getBackendTexture();
+    }
+    return GrBackendTexture(); // invalid
+}
+
+GrBackendRenderTarget SkSurface_Gpu::onGetBackendRenderTarget(BackendHandleAccess access) {
+    GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
+    if (!rt) {
+        return GrBackendRenderTarget(); // invalid
+    }
+
+    return rt->getBackendRenderTarget();
+}
+
 SkCanvas* SkSurface_Gpu::onNewCanvas() {
     SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
     flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index c23da72..ecb84a8 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -25,6 +25,10 @@
 
     GrBackendObject onGetTextureHandle(BackendHandleAccess) override;
     bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) override;
+
+    GrBackendTexture onGetBackendTexture(BackendHandleAccess) override;
+    GrBackendRenderTarget onGetBackendRenderTarget(BackendHandleAccess) override;
+
     SkCanvas* onNewCanvas() override;
     sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
     sk_sp<SkImage> onNewImageSnapshot() override;
diff --git a/tests/SpecialImageTest.cpp b/tests/SpecialImageTest.cpp
index 8397795..a9cd1c7 100644
--- a/tests/SpecialImageTest.cpp
+++ b/tests/SpecialImageTest.cpp
@@ -16,6 +16,7 @@
 #include "Test.h"
 
 #if SK_SUPPORT_GPU
+#include "GrBackendSurface.h"
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrProxyProvider.h"
@@ -126,17 +127,20 @@
         SkPixmap tmpPixmap;
         REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
     }
+#if SK_SUPPORT_GPU
     {
         SkImageFilter::OutputProperties outProps(img->getColorSpace());
         sk_sp<SkSurface> tightSurf(img->makeTightSurface(outProps, subset.size()));
 
         REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
         REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
-        REPORTER_ASSERT(reporter, isGPUBacked ==
-                     !!tightSurf->getTextureHandle(SkSurface::kDiscardWrite_BackendHandleAccess));
+        GrBackendTexture backendTex = tightSurf->getBackendTexture(
+                                                    SkSurface::kDiscardWrite_BackendHandleAccess);
+        REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
         SkPixmap tmpPixmap;
         REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
     }
+#endif
 }
 
 DEF_TEST(SpecialImage_Raster, reporter) {
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 744dd63..aa23998 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -285,62 +285,48 @@
         }
     }
 }
-#endif
 
-static GrBackendObject get_surface_backend_texture_handle(
-    SkSurface* s, SkSurface::BackendHandleAccess a) {
-    return s->getTextureHandle(a);
-}
-static GrBackendObject get_surface_backend_render_target_handle(
-    SkSurface* s, SkSurface::BackendHandleAccess a) {
-    GrBackendObject result;
-    if (!s->getRenderTargetHandle(&result, a)) {
-        return 0;
-    }
-    return result;
-}
-
-static void test_backend_handle_access_copy_on_write(
-    skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess mode,
-    GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) {
-    GrBackendObject obj1 = func(surface, mode);
+static void test_backend_texture_access_copy_on_write(
+    skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess access) {
+    GrBackendTexture tex1 = surface->getBackendTexture(access);
     sk_sp<SkImage> snap1(surface->makeImageSnapshot());
 
-    GrBackendObject obj2 = func(surface, mode);
+    GrBackendTexture tex2 = surface->getBackendTexture(access);
     sk_sp<SkImage> snap2(surface->makeImageSnapshot());
 
     // If the access mode triggers CoW, then the backend objects should reflect it.
-    REPORTER_ASSERT(reporter, (obj1 == obj2) == (snap1 == snap2));
+    REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(tex1, tex2) == (snap1 == snap2));
 }
-DEF_TEST(SurfaceBackendHandleAccessCopyOnWrite, reporter) {
+
+static void test_backend_rendertarget_access_copy_on_write(
+    skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess access) {
+    GrBackendRenderTarget rt1 = surface->getBackendRenderTarget(access);
+    sk_sp<SkImage> snap1(surface->makeImageSnapshot());
+
+    GrBackendRenderTarget rt2 = surface->getBackendRenderTarget(access);
+    sk_sp<SkImage> snap2(surface->makeImageSnapshot());
+
+    // If the access mode triggers CoW, then the backend objects should reflect it.
+    REPORTER_ASSERT(reporter, GrBackendRenderTarget::TestingOnly_Equals(rt1, rt2) ==
+                              (snap1 == snap2));
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendSurfaceAccessCopyOnWrite_Gpu, reporter, ctxInfo) {
     const SkSurface::BackendHandleAccess accessModes[] = {
         SkSurface::kFlushRead_BackendHandleAccess,
         SkSurface::kFlushWrite_BackendHandleAccess,
         SkSurface::kDiscardWrite_BackendHandleAccess,
     };
-    for (auto& handle_access_func :
-            { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) {
-        for (auto& accessMode : accessModes) {
-            auto surface(create_surface());
-            test_backend_handle_access_copy_on_write(reporter, surface.get(), accessMode,
-                                                     handle_access_func);
-        }
-    }
-}
-#if SK_SUPPORT_GPU
-DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessCopyOnWrite_Gpu, reporter, ctxInfo) {
-        const SkSurface::BackendHandleAccess accessModes[] = {
-        SkSurface::kFlushRead_BackendHandleAccess,
-        SkSurface::kFlushWrite_BackendHandleAccess,
-        SkSurface::kDiscardWrite_BackendHandleAccess,
-    };
+
     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
-        for (auto& handle_access_func :
-                { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) {
-            for (auto& accessMode : accessModes) {
+        for (auto& accessMode : accessModes) {
+            {
                 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
-                test_backend_handle_access_copy_on_write(reporter, surface.get(), accessMode,
-                                                         handle_access_func);
+                test_backend_texture_access_copy_on_write(reporter, surface.get(), accessMode);
+            }
+            {
+                auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
+                test_backend_rendertarget_access_copy_on_write(reporter, surface.get(), accessMode);
             }
         }
     }
@@ -349,38 +335,42 @@
 
 #if SK_SUPPORT_GPU
 
-static void test_backend_handle_unique_id(
-    skiatest::Reporter* reporter, SkSurface* surface,
-    GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) {
+template<typename Type, Type(SkSurface::*func)(SkSurface::BackendHandleAccess)>
+static void test_backend_unique_id(skiatest::Reporter* reporter, SkSurface* surface) {
     sk_sp<SkImage> image0(surface->makeImageSnapshot());
-    GrBackendObject obj = func(surface, SkSurface::kFlushRead_BackendHandleAccess);
-    REPORTER_ASSERT(reporter, obj != 0);
+
+    Type obj = (surface->*func)(SkSurface::kFlushRead_BackendHandleAccess);
+    REPORTER_ASSERT(reporter, obj.isValid());
     sk_sp<SkImage> image1(surface->makeImageSnapshot());
     // just read access should not affect the snapshot
     REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
 
-    obj = func(surface, SkSurface::kFlushWrite_BackendHandleAccess);
-    REPORTER_ASSERT(reporter, obj != 0);
+    obj = (surface->*func)(SkSurface::kFlushWrite_BackendHandleAccess);
+    REPORTER_ASSERT(reporter, obj.isValid());
     sk_sp<SkImage> image2(surface->makeImageSnapshot());
     // expect a new image, since we claimed we would write
     REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
 
-    obj = func(surface, SkSurface::kDiscardWrite_BackendHandleAccess);
-    REPORTER_ASSERT(reporter, obj != 0);
+    obj = (surface->*func)(SkSurface::kDiscardWrite_BackendHandleAccess);
+    REPORTER_ASSERT(reporter, obj.isValid());
     sk_sp<SkImage> image3(surface->makeImageSnapshot());
     // expect a new(er) image, since we claimed we would write
     REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
     REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
 }
+
 // No CPU test.
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessIDs_Gpu, reporter, ctxInfo) {
     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
-        for (auto& test_func : { &test_backend_handle_unique_id }) {
-            for (auto& handle_access_func :
-                { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle}) {
-                auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
-                test_func(reporter, surface.get(), handle_access_func);
-            }
+        {
+            auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
+            test_backend_unique_id<GrBackendTexture, &SkSurface::getBackendTexture>(reporter,
+                                                                                    surface.get());
+        }
+        {
+            auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
+            test_backend_unique_id<GrBackendRenderTarget, &SkSurface::getBackendRenderTarget>(
+                                                                reporter, surface.get());
         }
     }
 }