Remove GrBackendObject from tests (except image_from_yuv_textures)

This sets the stage for landing https://skia-review.googlesource.com/c/skia/+/82823 (Update SkImage::MakeFromYUVTexturesCopy to GrBackendTexture)

Change-Id: I2c62f23dc447b9ad55c0b5f06bcd6d7ca0ec4d2b
Reviewed-on: https://skia-review.googlesource.com/83920
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/gm/imagefromyuvtextures.cpp b/gm/imagefromyuvtextures.cpp
index 13e0300..7150669 100644
--- a/gm/imagefromyuvtextures.cpp
+++ b/gm/imagefromyuvtextures.cpp
@@ -101,10 +101,10 @@
 
         for (int i = 0; i < 3; ++i) {
             SkASSERT(fYUVBmps[i].width() == SkToInt(fYUVBmps[i].rowBytes()));
-            yuvHandles[i] = gpu->createTestingOnlyBackendTexture(fYUVBmps[i].getPixels(),
-                                                                 fYUVBmps[i].width(),
-                                                                 fYUVBmps[i].height(),
-                                                                 kAlpha_8_GrPixelConfig);
+            yuvHandles[i] = gpu->createTestingOnlyBackendObject(fYUVBmps[i].getPixels(),
+                                                                fYUVBmps[i].width(),
+                                                                fYUVBmps[i].height(),
+                                                                kAlpha_8_GrPixelConfig);
         }
         context->resetContext();
     }
@@ -117,7 +117,7 @@
         }
 
         for (int i = 0; i < 3; ++i) {
-            gpu->deleteTestingOnlyBackendTexture(yuvHandles[i]);
+            gpu->deleteTestingOnlyBackendObject(yuvHandles[i]);
         }
 
         context->resetContext();
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index cf91dbe..c020158 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -453,17 +453,31 @@
     /** Creates a texture directly in the backend API without wrapping it in a GrTexture. This is
         only to be used for testing (particularly for testing the methods that import an externally
         created texture into Skia. Must be matched with a call to deleteTestingOnlyTexture(). */
-    virtual GrBackendObject createTestingOnlyBackendTexture(
+    virtual GrBackendObject createTestingOnlyBackendObject(
                                                       void* pixels, int w, int h,
                                                       GrPixelConfig config,
                                                       bool isRenderTarget = false,
                                                       GrMipMapped mipMapped = GrMipMapped::kNo) = 0;
-    /** Check a handle represents an actual texture in the backend API that has not been freed. */
-    virtual bool isTestingOnlyBackendTexture(GrBackendObject) const = 0;
     /** If ownership of the backend texture has been transferred pass true for abandonTexture. This
         will do any necessary cleanup of the handle without freeing the texture in the backend
         API. */
-    virtual void deleteTestingOnlyBackendTexture(GrBackendObject,
+    virtual void deleteTestingOnlyBackendObject(GrBackendObject,
+                                                bool abandonTexture = false) = 0;
+
+    /** Creates a texture directly in the backend API without wrapping it in a GrTexture. This is
+        only to be used for testing (particularly for testing the methods that import an externally
+        created texture into Skia. Must be matched with a call to deleteTestingOnlyTexture(). */
+    virtual GrBackendTexture createTestingOnlyBackendTexture(
+                                                      void* pixels, int w, int h,
+                                                      GrPixelConfig config,
+                                                      bool isRenderTarget,
+                                                      GrMipMapped mipMapped) = 0;
+    /** Check a handle represents an actual texture in the backend API that has not been freed. */
+    virtual bool isTestingOnlyBackendTexture(const GrBackendTexture&) const = 0;
+    /** If ownership of the backend texture has been transferred pass true for abandonTexture. This
+        will do any necessary cleanup of the handle without freeing the texture in the backend
+        API. */
+    virtual void deleteTestingOnlyBackendTexture(GrBackendTexture*,
                                                  bool abandonTexture = false) = 0;
 
     // width and height may be larger than rt (if underlying API allows it).
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index ddb80b4..c114c6c 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -4387,9 +4387,9 @@
     }
 }
 
-GrBackendObject GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                         GrPixelConfig config, bool /*isRT*/,
-                                                         GrMipMapped mipMapped) {
+GrBackendObject GrGLGpu::createTestingOnlyBackendObject(void* pixels, int w, int h,
+                                                        GrPixelConfig config, bool /*isRT*/,
+                                                        GrMipMapped mipMapped) {
     if (!this->caps()->isConfigTexturable(config)) {
         return reinterpret_cast<GrBackendObject>(nullptr);
     }
@@ -4450,16 +4450,7 @@
     return reinterpret_cast<GrBackendObject>(info.release());
 }
 
-bool GrGLGpu::isTestingOnlyBackendTexture(GrBackendObject id) const {
-    GrGLuint texID = reinterpret_cast<const GrGLTextureInfo*>(id)->fID;
-
-    GrGLboolean result;
-    GL_CALL_RET(result, IsTexture(texID));
-
-    return (GR_GL_TRUE == result);
-}
-
-void GrGLGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandonTexture) {
+void GrGLGpu::deleteTestingOnlyBackendObject(GrBackendObject id, bool abandonTexture) {
     std::unique_ptr<const GrGLTextureInfo> info(reinterpret_cast<const GrGLTextureInfo*>(id));
     GrGLuint texID = info->fID;
 
@@ -4468,6 +4459,94 @@
     }
 }
 
+GrBackendTexture GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                          GrPixelConfig config, bool /*isRT*/,
+                                                          GrMipMapped mipMapped) {
+    if (!this->caps()->isConfigTexturable(config)) {
+        return GrBackendTexture();  // invalid
+    }
+
+    // Currently we don't support uploading pixel data when mipped.
+    if (pixels && GrMipMapped::kYes == mipMapped) {
+        return GrBackendTexture();  // invalid
+    }
+
+    GrGLTextureInfo info;
+    info.fTarget = GR_GL_TEXTURE_2D;
+    info.fID = 0;
+    GL_CALL(GenTextures(1, &info.fID));
+    GL_CALL(ActiveTexture(GR_GL_TEXTURE0));
+    GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+    GL_CALL(BindTexture(info.fTarget, info.fID));
+    fHWBoundTextureUniqueIDs[0].makeInvalid();
+    GL_CALL(TexParameteri(info.fTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
+    GL_CALL(TexParameteri(info.fTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
+    GL_CALL(TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
+    GL_CALL(TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
+
+    GrGLenum internalFormat;
+    GrGLenum externalFormat;
+    GrGLenum externalType;
+
+    if (!this->glCaps().getTexImageFormats(config, config, &internalFormat, &externalFormat,
+                                           &externalType)) {
+        return GrBackendTexture();  // invalid
+    }
+
+    this->unbindCpuToGpuXferBuffer();
+
+    // Figure out the number of mip levels.
+    int mipLevels = 1;
+    if (GrMipMapped::kYes == mipMapped) {
+        mipLevels = SkMipMap::ComputeLevelCount(w, h) + 1;
+    }
+
+    size_t bpp = GrBytesPerPixel(config);
+    size_t baseLayerSize = bpp * w * h;
+    SkAutoMalloc defaultStorage(baseLayerSize);
+    if (!pixels) {
+        // Fill in the texture with all zeros so we don't have random garbage
+        pixels = defaultStorage.get();
+        memset(pixels, 0, baseLayerSize);
+    }
+
+    int width = w;
+    int height = h;
+    for (int i = 0; i < mipLevels; ++i) {
+        GL_CALL(TexImage2D(info.fTarget, i, internalFormat, width, height, 0, externalFormat,
+                           externalType, pixels));
+        width = SkTMax(1, width / 2);
+        height = SkTMax(1, height / 2);
+    }
+
+    return GrBackendTexture(w, h, config, mipMapped, info);
+}
+
+bool GrGLGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
+    SkASSERT(kOpenGL_GrBackend == tex.backend());
+
+    const GrGLTextureInfo* info = tex.getGLTextureInfo();
+    if (!info) {
+        return false;
+    }
+
+    GrGLboolean result;
+    GL_CALL_RET(result, IsTexture(info->fID));
+
+    return (GR_GL_TRUE == result);
+}
+
+void GrGLGpu::deleteTestingOnlyBackendTexture(GrBackendTexture* tex, bool abandonTexture) {
+    SkASSERT(kOpenGL_GrBackend == tex->backend());
+
+    const GrGLTextureInfo* info = tex->getGLTextureInfo();
+    if (info && !abandonTexture) {
+        GrGLuint texID = info->fID;
+
+        GL_CALL(DeleteTextures(1, &texID));
+    }
+}
+
 void GrGLGpu::resetShaderCacheForTesting() const {
     fProgramCache->abandon();
 }
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 3d9533d..42897ab 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -161,12 +161,18 @@
                                                                 int width,
                                                                 int height) override;
 
-    GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                    GrPixelConfig config,
-                                                    bool isRenderTarget,
-                                                    GrMipMapped mipMapped) override;
-    bool isTestingOnlyBackendTexture(GrBackendObject) const override;
-    void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override;
+    GrBackendObject createTestingOnlyBackendObject(void* pixels, int w, int h,
+                                                   GrPixelConfig config,
+                                                   bool isRenderTarget,
+                                                   GrMipMapped mipMapped) override;
+    void deleteTestingOnlyBackendObject(GrBackendObject, bool abandonTexture) override;
+
+    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                     GrPixelConfig config,
+                                                     bool isRenderTarget,
+                                                     GrMipMapped mipMapped) override;
+    bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
+    void deleteTestingOnlyBackendTexture(GrBackendTexture*, bool abandonTexture = false) override;
 
     void resetShaderCacheForTesting() const override;
 
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index 5969f2f..4080019 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -90,22 +90,46 @@
     return new GrMockStencilAttachment(this, width, height, kBits, rt->numColorSamples());
 }
 
-GrBackendObject GrMockGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                           GrPixelConfig config, bool isRT,
-                                                           GrMipMapped) {
+GrBackendObject GrMockGpu::createTestingOnlyBackendObject(void* pixels, int w, int h,
+                                                          GrPixelConfig config, bool isRT,
+                                                          GrMipMapped) {
     auto info = new GrMockTextureInfo;
     info->fID = NextExternalTextureID();
     fOutstandingTestingOnlyTextureIDs.add(info->fID);
     return reinterpret_cast<GrBackendObject>(info);
 }
 
-bool GrMockGpu::isTestingOnlyBackendTexture(GrBackendObject object) const {
-    return fOutstandingTestingOnlyTextureIDs.contains(
-            reinterpret_cast<const GrMockTextureInfo*>(object)->fID);
-}
-
-void GrMockGpu::deleteTestingOnlyBackendTexture(GrBackendObject object, bool abandonTexture) {
+void GrMockGpu::deleteTestingOnlyBackendObject(GrBackendObject object, bool abandonTexture) {
     auto info = reinterpret_cast<const GrMockTextureInfo*>(object);
     fOutstandingTestingOnlyTextureIDs.remove(info->fID);
     delete info;
 }
+
+GrBackendTexture GrMockGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                            GrPixelConfig config, bool isRT,
+                                                            GrMipMapped) {
+    GrMockTextureInfo info;
+    info.fID = NextExternalTextureID();
+    fOutstandingTestingOnlyTextureIDs.add(info.fID);
+    return GrBackendTexture(w, h, config, info);
+}
+
+bool GrMockGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
+    SkASSERT(kMock_GrBackend == tex.backend());
+
+    const GrMockTextureInfo* info = tex.getMockTextureInfo();
+    if (!info) {
+        return false;
+    }
+
+    return fOutstandingTestingOnlyTextureIDs.contains(info->fID);
+}
+
+void GrMockGpu::deleteTestingOnlyBackendTexture(GrBackendTexture* tex, bool abandonTexture) {
+    SkASSERT(kMock_GrBackend == tex->backend());
+
+    const GrMockTextureInfo* info = tex->getMockTextureInfo();
+    if (info) {
+        fOutstandingTestingOnlyTextureIDs.remove(info->fID);
+    }
+}
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 2a86a4e..aaa465b 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -129,12 +129,14 @@
                                                                 int height) override;
     void clearStencil(GrRenderTarget*, int clearValue) override  {}
 
-    GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h, GrPixelConfig,
+    GrBackendObject createTestingOnlyBackendObject(void* pixels, int w, int h, GrPixelConfig,
+                                                   bool isRT, GrMipMapped) override;
+    void deleteTestingOnlyBackendObject(GrBackendObject, bool abandonTexture) override;
+
+    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h, GrPixelConfig,
                                                     bool isRT, GrMipMapped) override;
-
-    bool isTestingOnlyBackendTexture(GrBackendObject) const override;
-
-    void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override;
+    bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
+    void deleteTestingOnlyBackendTexture(GrBackendTexture*, bool abandonTexture = false) override;
 
     static int NextInternalTextureID();
     static int NextExternalTextureID();
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 4dde825..6d30d1b 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -141,13 +141,20 @@
 
     void clearStencil(GrRenderTarget* target, int clearValue) override  {}
 
-    GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                    GrPixelConfig config, bool isRT,
-                                                    GrMipMapped) override {
+    GrBackendObject createTestingOnlyBackendObject(void* pixels, int w, int h,
+                                                   GrPixelConfig config, bool isRT,
+                                                   GrMipMapped) override {
         return 0;
     }
-    bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return false; }
-    void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override {}
+    void deleteTestingOnlyBackendObject(GrBackendObject, bool abandonTexture = false) override {}
+
+    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                     GrPixelConfig config, bool isRT,
+                                                     GrMipMapped) override {
+        return GrBackendTexture();
+    }
+    bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override { return false; }
+    void deleteTestingOnlyBackendTexture(GrBackendTexture*, bool abandon = false) override {}
 
     sk_sp<GrMtlCaps> fMtlCaps;
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 0a64234..85ddd08 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1173,10 +1173,10 @@
     return true;
 }
 
-GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h,
-                                                         GrPixelConfig config,
-                                                         bool isRenderTarget,
-                                                         GrMipMapped mipMapped) {
+GrBackendObject GrVkGpu::createTestingOnlyBackendObject(void* srcData, int w, int h,
+                                                        GrPixelConfig config,
+                                                        bool isRenderTarget,
+                                                        GrMipMapped mipMapped) {
 
     VkFormat pixelFormat;
     if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
@@ -1508,8 +1508,357 @@
     return (GrBackendObject)info;
 }
 
-bool GrVkGpu::isTestingOnlyBackendTexture(GrBackendObject id) const {
-    const GrVkImageInfo* backend = reinterpret_cast<const GrVkImageInfo*>(id);
+void GrVkGpu::deleteTestingOnlyBackendObject(GrBackendObject id, bool abandon) {
+    GrVkImageInfo* backend = reinterpret_cast<GrVkImageInfo*>(id);
+    if (backend) {
+        if (!abandon) {
+            // something in the command buffer may still be using this, so force submit
+            this->submitCommandBuffer(kForce_SyncQueue);
+            GrVkImage::DestroyImageInfo(this, backend);
+        }
+        delete backend;
+    }
+}
+
+GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h,
+                                                          GrPixelConfig config,
+                                                          bool isRenderTarget,
+                                                          GrMipMapped mipMapped) {
+
+    VkFormat pixelFormat;
+    if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
+        return GrBackendTexture(); // invalid
+    }
+
+    bool linearTiling = false;
+    if (!fVkCaps->isConfigTexturable(config)) {
+        return GrBackendTexture(); // invalid
+    }
+
+    if (isRenderTarget && !fVkCaps->isConfigRenderable(config, false)) {
+        return GrBackendTexture(); // invalid
+    }
+
+    // Currently we don't support uploading pixel data when mipped.
+    if (srcData && GrMipMapped::kYes == mipMapped) {
+        return GrBackendTexture(); // invalid
+    }
+
+    if (fVkCaps->isConfigTexturableLinearly(config) &&
+        (!isRenderTarget || fVkCaps->isConfigRenderableLinearly(config, false)) &&
+        GrMipMapped::kNo == mipMapped) {
+        linearTiling = true;
+    }
+
+    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
+    usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+    usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    if (isRenderTarget) {
+        usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    }
+
+    VkImage image = VK_NULL_HANDLE;
+    GrVkAlloc alloc = { VK_NULL_HANDLE, 0, 0, 0 };
+
+    VkImageTiling imageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
+    VkImageLayout initialLayout = (VK_IMAGE_TILING_LINEAR == imageTiling)
+                                ? VK_IMAGE_LAYOUT_PREINITIALIZED
+                                : VK_IMAGE_LAYOUT_UNDEFINED;
+
+    // Create Image
+    VkSampleCountFlagBits vkSamples;
+    if (!GrSampleCountToVkSampleCount(1, &vkSamples)) {
+        return GrBackendTexture(); // invalid
+    }
+
+    // Figure out the number of mip levels.
+    uint32_t mipLevels = 1;
+    if (GrMipMapped::kYes == mipMapped) {
+        mipLevels = SkMipMap::ComputeLevelCount(w, h) + 1;
+    }
+
+    const VkImageCreateInfo imageCreateInfo = {
+        VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
+        nullptr,                                     // pNext
+        0,                                           // VkImageCreateFlags
+        VK_IMAGE_TYPE_2D,                            // VkImageType
+        pixelFormat,                                 // VkFormat
+        { (uint32_t) w, (uint32_t) h, 1 },           // VkExtent3D
+        mipLevels,                                   // mipLevels
+        1,                                           // arrayLayers
+        vkSamples,                                   // samples
+        imageTiling,                                 // VkImageTiling
+        usageFlags,                                  // VkImageUsageFlags
+        VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
+        0,                                           // queueFamilyCount
+        0,                                           // pQueueFamilyIndices
+        initialLayout                                // initialLayout
+    };
+
+    GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateImage(this->device(), &imageCreateInfo, nullptr, &image));
+
+    if (!GrVkMemory::AllocAndBindImageMemory(this, image, linearTiling, &alloc)) {
+        VK_CALL(DestroyImage(this->device(), image, nullptr));
+        return GrBackendTexture(); // invalid
+    }
+
+    // We need to declare these early so that we can delete them at the end outside of the if block.
+    GrVkAlloc bufferAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+    VkBuffer buffer = VK_NULL_HANDLE;
+
+    VkResult err;
+    const VkCommandBufferAllocateInfo cmdInfo = {
+        VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
+        nullptr,                                          // pNext
+        fCmdPool,                                         // commandPool
+        VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
+        1                                                 // bufferCount
+    };
+
+    VkCommandBuffer cmdBuffer;
+    err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer));
+    if (err) {
+        GrVkMemory::FreeImageMemory(this, false, alloc);
+        VK_CALL(DestroyImage(fDevice, image, nullptr));
+        return GrBackendTexture(); // invalid
+    }
+
+    VkCommandBufferBeginInfo cmdBufferBeginInfo;
+    memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
+    cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cmdBufferBeginInfo.pNext = nullptr;
+    cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    cmdBufferBeginInfo.pInheritanceInfo = nullptr;
+
+    err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
+    SkASSERT(!err);
+
+    size_t bpp = GrBytesPerPixel(config);
+    size_t rowCopyBytes = bpp * w;
+    if (linearTiling) {
+        const VkImageSubresource subres = {
+            VK_IMAGE_ASPECT_COLOR_BIT,
+            0,  // mipLevel
+            0,  // arraySlice
+        };
+        VkSubresourceLayout layout;
+
+        VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout));
+
+        if (!copy_testing_data(this, srcData, alloc, 0, rowCopyBytes,
+                               static_cast<size_t>(layout.rowPitch), h)) {
+            GrVkMemory::FreeImageMemory(this, true, alloc);
+            VK_CALL(DestroyImage(fDevice, image, nullptr));
+            VK_CALL(EndCommandBuffer(cmdBuffer));
+            VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
+            return GrBackendTexture(); // invalid
+        }
+    } else {
+        SkASSERT(w && h);
+
+        SkTArray<size_t> individualMipOffsets(mipLevels);
+        individualMipOffsets.push_back(0);
+        size_t combinedBufferSize = w * bpp * h;
+        int currentWidth = w;
+        int currentHeight = h;
+        // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
+        // config. This works with the assumption that the bytes in pixel config is always a power
+        // of 2.
+        SkASSERT((bpp & (bpp - 1)) == 0);
+        const size_t alignmentMask = 0x3 | (bpp - 1);
+        for (uint32_t currentMipLevel = 1; currentMipLevel < mipLevels; currentMipLevel++) {
+            currentWidth = SkTMax(1, currentWidth/2);
+            currentHeight = SkTMax(1, currentHeight/2);
+
+            const size_t trimmedSize = currentWidth * bpp * currentHeight;
+            const size_t alignmentDiff = combinedBufferSize & alignmentMask;
+            if (alignmentDiff != 0) {
+                combinedBufferSize += alignmentMask - alignmentDiff + 1;
+            }
+            individualMipOffsets.push_back(combinedBufferSize);
+            combinedBufferSize += trimmedSize;
+        }
+
+        VkBufferCreateInfo bufInfo;
+        memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
+        bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+        bufInfo.flags = 0;
+        bufInfo.size = combinedBufferSize;
+        bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+        bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+        bufInfo.queueFamilyIndexCount = 0;
+        bufInfo.pQueueFamilyIndices = nullptr;
+        err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer));
+
+        if (err) {
+            GrVkMemory::FreeImageMemory(this, false, alloc);
+            VK_CALL(DestroyImage(fDevice, image, nullptr));
+            VK_CALL(EndCommandBuffer(cmdBuffer));
+            VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
+            return GrBackendTexture(); // invalid
+        }
+
+        if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type,
+                                                  true, &bufferAlloc)) {
+            GrVkMemory::FreeImageMemory(this, false, alloc);
+            VK_CALL(DestroyImage(fDevice, image, nullptr));
+            VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
+            VK_CALL(EndCommandBuffer(cmdBuffer));
+            VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
+            return GrBackendTexture(); // invalid
+        }
+
+        currentWidth = w;
+        currentHeight = h;
+        for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
+            SkASSERT(0 == currentMipLevel || !srcData);
+            size_t currentRowBytes = bpp * currentWidth;
+            size_t bufferOffset = individualMipOffsets[currentMipLevel];
+            if (!copy_testing_data(this, srcData, bufferAlloc, bufferOffset,
+                                   currentRowBytes, currentRowBytes, currentHeight)) {
+                GrVkMemory::FreeImageMemory(this, false, alloc);
+                VK_CALL(DestroyImage(fDevice, image, nullptr));
+                GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
+                VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
+                VK_CALL(EndCommandBuffer(cmdBuffer));
+                VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
+                return GrBackendTexture(); // invalid
+            }
+            currentWidth = SkTMax(1, currentWidth/2);
+            currentHeight = SkTMax(1, currentHeight/2);
+        }
+
+        // Set image layout and add barrier
+        VkImageMemoryBarrier barrier;
+        memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
+        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+        barrier.pNext = nullptr;
+        barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout);
+        barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+        barrier.oldLayout = initialLayout;
+        barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+        barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        barrier.image = image;
+        barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0 , 1};
+
+        VK_CALL(CmdPipelineBarrier(cmdBuffer,
+                                   GrVkMemory::LayoutToPipelineStageFlags(initialLayout),
+                                   VK_PIPELINE_STAGE_TRANSFER_BIT,
+                                   0,
+                                   0, nullptr,
+                                   0, nullptr,
+                                   1, &barrier));
+        initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+
+        SkTArray<VkBufferImageCopy> regions(mipLevels);
+
+        currentWidth = w;
+        currentHeight = h;
+        for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
+            // Submit copy command
+            VkBufferImageCopy& region = regions.push_back();
+            memset(&region, 0, sizeof(VkBufferImageCopy));
+            region.bufferOffset = individualMipOffsets[currentMipLevel];
+            region.bufferRowLength = currentWidth;
+            region.bufferImageHeight = currentHeight;
+            region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+            region.imageOffset = { 0, 0, 0 };
+            region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
+            currentWidth = SkTMax(1, currentWidth/2);
+            currentHeight = SkTMax(1, currentHeight/2);
+        }
+
+        VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, regions.count(),
+                                     regions.begin()));
+    }
+    // Change Image layout to shader read since if we use this texture as a borrowed textures within
+    // Ganesh we require that its layout be set to that
+    VkImageMemoryBarrier barrier;
+    memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
+    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barrier.pNext = nullptr;
+    barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout);
+    barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+    barrier.oldLayout = initialLayout;
+    barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.image = image;
+    barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0 , 1};
+
+    VK_CALL(CmdPipelineBarrier(cmdBuffer,
+                               GrVkMemory::LayoutToPipelineStageFlags(initialLayout),
+                               VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+                               0,
+                               0, nullptr,
+                               0, nullptr,
+                               1, &barrier));
+
+    // End CommandBuffer
+    err = VK_CALL(EndCommandBuffer(cmdBuffer));
+    SkASSERT(!err);
+
+    // Create Fence for queue
+    VkFence fence;
+    VkFenceCreateInfo fenceInfo;
+    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
+    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+
+    err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence));
+    SkASSERT(!err);
+
+    VkSubmitInfo submitInfo;
+    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.pNext = nullptr;
+    submitInfo.waitSemaphoreCount = 0;
+    submitInfo.pWaitSemaphores = nullptr;
+    submitInfo.pWaitDstStageMask = 0;
+    submitInfo.commandBufferCount = 1;
+    submitInfo.pCommandBuffers = &cmdBuffer;
+    submitInfo.signalSemaphoreCount = 0;
+    submitInfo.pSignalSemaphores = nullptr;
+    err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence));
+    SkASSERT(!err);
+
+    err = VK_CALL(WaitForFences(fDevice, 1, &fence, true, UINT64_MAX));
+    if (VK_TIMEOUT == err) {
+        GrVkMemory::FreeImageMemory(this, false, alloc);
+        VK_CALL(DestroyImage(fDevice, image, nullptr));
+        GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
+        VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
+        VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
+        VK_CALL(DestroyFence(fDevice, fence, nullptr));
+        SkDebugf("Fence failed to signal: %d\n", err);
+        SK_ABORT("failing");
+    }
+    SkASSERT(!err);
+
+    // Clean up transfer resources
+    if (buffer != VK_NULL_HANDLE) { // workaround for an older NVidia driver crash
+        GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
+        VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
+    }
+    VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
+    VK_CALL(DestroyFence(fDevice, fence, nullptr));
+
+
+    GrVkImageInfo info;
+    info.fImage = image;
+    info.fAlloc = alloc;
+    info.fImageTiling = imageTiling;
+    info.fImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    info.fFormat = pixelFormat;
+    info.fLevelCount = mipLevels;
+
+    return GrBackendTexture(w, h, info);
+}
+
+bool GrVkGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
+    SkASSERT(kVulkan_GrBackend == tex.fBackend);
+
+    const GrVkImageInfo* backend = tex.getVkImageInfo();
 
     if (backend && backend->fImage && backend->fAlloc.fMemory) {
         VkMemoryRequirements req;
@@ -1525,15 +1874,15 @@
     return false;
 }
 
-void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandon) {
-    GrVkImageInfo* backend = reinterpret_cast<GrVkImageInfo*>(id);
-    if (backend) {
-        if (!abandon) {
-            // something in the command buffer may still be using this, so force submit
-            this->submitCommandBuffer(kForce_SyncQueue);
-            GrVkImage::DestroyImageInfo(this, backend);
-        }
-        delete backend;
+void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendTexture* tex, bool abandon) {
+    SkASSERT(kVulkan_GrBackend == tex->fBackend);
+
+    const GrVkImageInfo* info = tex->getVkImageInfo();
+
+    if (info && !abandon) {
+        // something in the command buffer may still be using this, so force submit
+        this->submitCommandBuffer(kForce_SyncQueue);
+        GrVkImage::DestroyImageInfo(this, const_cast<GrVkImageInfo*>(info));
     }
 }
 
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 75c7cb8..dd45ed1 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -85,12 +85,18 @@
 
     void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
 
-    GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                    GrPixelConfig config,
-                                                    bool isRenderTarget,
-                                                    GrMipMapped) override;
-    bool isTestingOnlyBackendTexture(GrBackendObject id) const override;
-    void deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandonTexture) override;
+    GrBackendObject createTestingOnlyBackendObject(void* pixels, int w, int h,
+                                                   GrPixelConfig config,
+                                                   bool isRenderTarget,
+                                                   GrMipMapped) override;
+    void deleteTestingOnlyBackendObject(GrBackendObject id, bool abandonTexture) override;
+
+    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                     GrPixelConfig config,
+                                                     bool isRenderTarget,
+                                                     GrMipMapped) override;
+    bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
+    void deleteTestingOnlyBackendTexture(GrBackendTexture*, bool abandonTexture = false) override;
 
     GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
                                                                 int width,
diff --git a/tests/EGLImageTest.cpp b/tests/EGLImageTest.cpp
index 53ff6f9..9ea6379 100644
--- a/tests/EGLImageTest.cpp
+++ b/tests/EGLImageTest.cpp
@@ -22,15 +22,14 @@
 using sk_gpu_test::GLTestContext;
 
 static void cleanup(GLTestContext* glctx0, GrGLuint texID0, GLTestContext* glctx1,
-                    sk_sp<GrContext> grctx1, const GrGLTextureInfo* grbackendtex1,
+                    sk_sp<GrContext> grctx1, GrBackendTexture* backendTex1,
                     GrEGLImage image1) {
     if (glctx1) {
         glctx1->makeCurrent();
         if (grctx1) {
-            if (grbackendtex1) {
+            if (backendTex1 && backendTex1->isValid()) {
                 GrGLGpu* gpu1 = static_cast<GrGLGpu*>(grctx1->getGpu());
-                GrBackendObject handle = reinterpret_cast<GrBackendObject>(grbackendtex1);
-                gpu1->deleteTestingOnlyBackendTexture(handle, false);
+                gpu1->deleteTestingOnlyBackendTexture(backendTex1);
             }
         }
         if (GR_EGL_NO_IMAGE != image1) {
@@ -64,19 +63,19 @@
         return;
     }
     sk_sp<GrContext> context1 = GrContext::MakeGL(sk_ref_sp(glCtx1->gl()));
-    const GrGLTextureInfo* backendTexture1 = nullptr;
+    GrBackendTexture backendTexture1;
     GrEGLImage image = GR_EGL_NO_IMAGE;
     GrGLTextureInfo externalTexture;
     externalTexture.fID = 0;
 
     if (!context1) {
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
 
     if (!glCtx1->gl()->hasExtension("EGL_KHR_image") ||
         !glCtx1->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
 
@@ -86,24 +85,28 @@
     context1->flush();
     GrGpu* gpu1 = context1->getGpu();
     static const int kSize = 100;
-    backendTexture1 = reinterpret_cast<const GrGLTextureInfo*>(
-        gpu1->createTestingOnlyBackendTexture(nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig));
-    if (!backendTexture1 || !backendTexture1->fID) {
+    backendTexture1 =
+        gpu1->createTestingOnlyBackendTexture(nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig,
+                                              false, GrMipMapped::kNo);
+    if (!gpu1->isTestingOnlyBackendTexture(backendTexture1)) {
         ERRORF(reporter, "Error creating texture for EGL Image");
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
-    if (GR_GL_TEXTURE_2D != backendTexture1->fTarget) {
+
+    const GrGLTextureInfo* texInfo = backendTexture1.getGLTextureInfo();
+
+    if (GR_GL_TEXTURE_2D != texInfo->fTarget) {
         ERRORF(reporter, "Expected backend texture to be 2D");
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
 
     // Wrap the texture in an EGLImage
-    image = glCtx1->texture2DToEGLImage(backendTexture1->fID);
+    image = glCtx1->texture2DToEGLImage(texInfo->fID);
     if (GR_EGL_NO_IMAGE == image) {
         ERRORF(reporter, "Error creating EGL Image from texture");
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
 
@@ -121,8 +124,8 @@
         pixels.get()[i] = 0xDDAABBCC;
     }
     GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0));
-    GR_GL_CALL(glCtx1->gl(), BindTexture(backendTexture1->fTarget, backendTexture1->fID));
-    GR_GL_CALL(glCtx1->gl(), TexSubImage2D(backendTexture1->fTarget, 0, 0, 0, kSize, kSize,
+    GR_GL_CALL(glCtx1->gl(), BindTexture(texInfo->fTarget, texInfo->fID));
+    GR_GL_CALL(glCtx1->gl(), TexSubImage2D(texInfo->fTarget, 0, 0, 0, kSize, kSize,
                                            GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get()));
     GR_GL_CALL(glCtx1->gl(), Finish());
     // We've been making direct GL calls in GL context 1, let GrContext 1 know its internal
@@ -137,7 +140,7 @@
     externalTexture.fID = glCtx0->eglImageToExternalTexture(image);
     if (0 == externalTexture.fID) {
         ERRORF(reporter, "Error converting EGL Image back to texture");
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
 
@@ -151,7 +154,7 @@
 
     if (!surfaceContext) {
         ERRORF(reporter, "Error wrapping external texture in GrSurfaceContext.");
-        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+        cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
         return;
     }
 
@@ -175,7 +178,7 @@
     test_copy_from_surface(reporter, context0, surfaceContext->asSurfaceProxy(),
                            pixels.get(), true, "EGLImageTest-copy");
 
-    cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image);
+    cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, &backendTexture1, image);
 }
 
 #endif
diff --git a/tests/GrMipMappedTest.cpp b/tests/GrMipMappedTest.cpp
index ff9d76d..7caa4bb 100644
--- a/tests/GrMipMappedTest.cpp
+++ b/tests/GrMipMappedTest.cpp
@@ -42,17 +42,9 @@
             // CreateTestingOnlyBackendTexture currently doesn't support uploading data to mip maps
             // so we don't send any. However, we pretend there is data for the checks below which is
             // fine since we are never actually using these textures for any work on the gpu.
-            GrBackendObject backendHandle = context->getGpu()->createTestingOnlyBackendTexture(
+            GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture(
                     nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, isRT, mipMapped);
 
-            GrBackend backend = context->contextPriv().getBackend();
-            GrBackendTexture backendTex = GrTest::CreateBackendTexture(backend,
-                                                                       kSize,
-                                                                       kSize,
-                                                                       kRGBA_8888_GrPixelConfig,
-                                                                       mipMapped,
-                                                                       backendHandle);
-
             sk_sp<GrTextureProxy> proxy;
             sk_sp<SkImage> image;
             if (isRT) {
@@ -74,7 +66,7 @@
             }
             REPORTER_ASSERT(reporter, proxy);
             if (!proxy) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
@@ -83,7 +75,7 @@
             GrTexture* texture = proxy->priv().peekTexture();
             REPORTER_ASSERT(reporter, texture);
             if (!texture) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
@@ -97,7 +89,7 @@
             } else {
                 REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
             }
-            context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+            context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }
@@ -111,17 +103,9 @@
     }
     for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
         for (auto willUseMips : {false, true}) {
-            GrBackendObject backendHandle = context->getGpu()->createTestingOnlyBackendTexture(
+            GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture(
                     nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, mipMapped);
 
-            GrBackend backend = context->contextPriv().getBackend();
-            GrBackendTexture backendTex = GrTest::CreateBackendTexture(backend,
-                                                                       kSize,
-                                                                       kSize,
-                                                                       kRGBA_8888_GrPixelConfig,
-                                                                       mipMapped,
-                                                                       backendHandle);
-
             sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
                                                             kTopLeft_GrSurfaceOrigin,
                                                             kPremul_SkAlphaType, nullptr);
@@ -129,7 +113,7 @@
             GrTextureProxy* proxy = as_IB(image)->peekProxy();
             REPORTER_ASSERT(reporter, proxy);
             if (!proxy) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
@@ -138,7 +122,7 @@
             sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
             REPORTER_ASSERT(reporter, texture);
             if (!texture) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
@@ -146,7 +130,7 @@
                     texture, kTopLeft_GrSurfaceOrigin, nullptr, kPremul_SkAlphaType, nullptr);
             REPORTER_ASSERT(reporter, imageGen);
             if (!imageGen) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
@@ -162,7 +146,7 @@
 
             REPORTER_ASSERT(reporter, genProxy);
             if (!genProxy) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
@@ -171,13 +155,13 @@
             GrTexture* genTexture = genProxy->priv().peekTexture();
             REPORTER_ASSERT(reporter, genTexture);
             if (!genTexture) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 return;
             }
 
             GrBackendObject genBackendObject = genTexture->getTextureHandle();
 
-            if (kOpenGL_GrBackend == backend) {
+            if (kOpenGL_GrBackend == context->contextPriv().getBackend()) {
                 const GrGLTextureInfo* origTexInfo = backendTex.getGLTextureInfo();
                 GrGLTextureInfo* genTexInfo = (GrGLTextureInfo*)genBackendObject;
                 if (willUseMips && GrMipMapped::kNo == mipMapped) {
@@ -186,7 +170,7 @@
                 } else {
                     REPORTER_ASSERT(reporter, origTexInfo->fID == genTexInfo->fID);
                 }
-            } else if (kVulkan_GrBackend == backend) {
+            } else if (kVulkan_GrBackend == context->contextPriv().getBackend()) {
 #ifdef SK_VULKAN
                 const GrVkImageInfo* origImageInfo = backendTex.getVkImageInfo();
                 GrVkImageInfo* genImageInfo = (GrVkImageInfo*)genBackendObject;
@@ -197,7 +181,7 @@
                     REPORTER_ASSERT(reporter, origImageInfo->fImage == genImageInfo->fImage);
                 }
 #endif
-            } else if (kMetal_GrBackend == backend) {
+            } else if (kMetal_GrBackend == context->contextPriv().getBackend()) {
                 REPORTER_ASSERT(reporter, false);
             } else {
                 REPORTER_ASSERT(reporter, false);
@@ -213,7 +197,7 @@
             bitmap.allocPixels(imageInfo);
             surfContext->readPixels(imageInfo, bitmap.getPixels(), 0, 0, 0, 0);
 
-            context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+            context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }
@@ -230,17 +214,9 @@
         for (auto isWrapped : {false, true}) {
             GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
             sk_sp<SkSurface> surface;
-            GrBackendObject backendHandle = context->getGpu()->createTestingOnlyBackendTexture(
-                    nullptr, 8, 8, kRGBA_8888_GrPixelConfig, true, mipMapped);
+            GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture(
+                    nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, true, mipMapped);
             if (isWrapped) {
-                GrBackend backend = context->contextPriv().getBackend();
-                GrBackendTexture backendTex = GrTest::CreateBackendTexture(backend,
-                                                                           kSize,
-                                                                           kSize,
-                                                                           kRGBA_8888_GrPixelConfig,
-                                                                           mipMapped,
-                                                                           backendHandle);
-
                 surface = SkSurface::MakeFromBackendTexture(context,
                                                             backendTex,
                                                             kTopLeft_GrSurfaceOrigin,
@@ -256,7 +232,7 @@
             }
             REPORTER_ASSERT(reporter, surface);
             if (!surface) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
             }
             SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
             GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
@@ -269,7 +245,7 @@
             sk_sp<SkImage> image = surface->makeImageSnapshot();
             REPORTER_ASSERT(reporter, image);
             if (!image) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
             }
             texProxy = as_IB(image)->peekProxy();
             REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
@@ -281,7 +257,7 @@
             // Must flush the context to make sure all the cmds (copies, etc.) from above are sent
             // to the gpu before we delete the backendHandle.
             context->flush();
-            context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+            context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }
diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp
index ddfcdef..137d2aa 100644
--- a/tests/GrPorterDuffTest.cpp
+++ b/tests/GrPorterDuffTest.cpp
@@ -1066,14 +1066,9 @@
         return;
     }
 
-    GrBackendObject backendTexHandle =
-        ctx->getGpu()->createTestingOnlyBackendTexture(nullptr, 100, 100, kRGBA_8888_GrPixelConfig);
-    GrBackendTexture backendTex = GrTest::CreateBackendTexture(ctx->contextPriv().getBackend(),
-                                                               100,
-                                                               100,
-                                                               kRGBA_8888_GrPixelConfig,
-                                                               GrMipMapped::kNo,
-                                                               backendTexHandle);
+    GrBackendTexture backendTex =
+        ctx->getGpu()->createTestingOnlyBackendTexture(nullptr, 100, 100, kRGBA_8888_GrPixelConfig,
+                                                       false, GrMipMapped::kNo);
 
     GrXferProcessor::DstProxy fakeDstProxy;
     {
@@ -1104,7 +1099,7 @@
             }
         }
     }
-    ctx->getGpu()->deleteTestingOnlyBackendTexture(backendTexHandle);
+    ctx->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
 }
 
 #endif
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index 8cb6f7e..0cd97f1 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -48,14 +48,8 @@
     REPORTER_ASSERT(reporter, tex1.get() == tex1->asTexture());
     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(tex1.get()) == tex1->asTexture());
 
-    GrBackendObject backendTexHandle = context->getGpu()->createTestingOnlyBackendTexture(
-        nullptr, 256, 256, kRGBA_8888_GrPixelConfig);
-    GrBackendTexture backendTex = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                               256,
-                                                               256,
-                                                               kRGBA_8888_GrPixelConfig,
-                                                               GrMipMapped::kNo,
-                                                               backendTexHandle);
+    GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture(
+        nullptr, 256, 256, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
 
     sk_sp<GrSurface> texRT2 = context->resourceProvider()->wrapRenderableBackendTexture(
             backendTex, 0, kBorrow_GrWrapOwnership);
@@ -69,7 +63,7 @@
     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
                     static_cast<GrSurface*>(texRT2->asTexture()));
 
-    context->getGpu()->deleteTestingOnlyBackendTexture(backendTexHandle);
+    context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
 }
 
 // This test checks that the isConfigTexturable and isConfigRenderable are
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index 1ba3f1d..483fbf7 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -767,16 +767,8 @@
 
     GrContext* ctx = ctxInfo.grContext();
 
-    GrBackendObject backendTexHandle =
-            ctxInfo.grContext()->getGpu()->createTestingOnlyBackendTexture(
-                    pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true);
-
-    GrBackendTexture backendTex = GrTest::CreateBackendTexture(ctx->contextPriv().getBackend(),
-                                                               kWidth,
-                                                               kHeight,
-                                                               kRGBA_8888_GrPixelConfig,
-                                                               GrMipMapped::kNo,
-                                                               backendTexHandle);
+    GrBackendTexture backendTex = ctxInfo.grContext()->getGpu()->createTestingOnlyBackendTexture(
+               pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
 
     TextureReleaseChecker releaseChecker;
     GrSurfaceOrigin texOrigin = kBottomLeft_GrSurfaceOrigin;
@@ -806,7 +798,7 @@
     refImg.reset(nullptr); // force a release of the image
     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
 
-    ctxInfo.grContext()->getGpu()->deleteTestingOnlyBackendTexture(backendTexHandle);
+    ctxInfo.grContext()->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
 }
 
 static void test_cross_context_image(skiatest::Reporter* reporter, const GrContextOptions& options,
diff --git a/tests/ResourceAllocatorTest.cpp b/tests/ResourceAllocatorTest.cpp
index 02785e6..c74a8bd 100644
--- a/tests/ResourceAllocatorTest.cpp
+++ b/tests/ResourceAllocatorTest.cpp
@@ -45,23 +45,18 @@
 }
 
 static sk_sp<GrSurfaceProxy> make_backend(GrContext* context, const ProxyParams& p,
-                                          GrBackendObject* backendTexHandle) {
-    *backendTexHandle = context->getGpu()->createTestingOnlyBackendTexture(
-                                                            nullptr, p.fSize, p.fSize, p.fConfig);
-    GrBackendTexture backendTex = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                               p.fSize,
-                                                               p.fSize,
-                                                               p.fConfig,
-                                                               GrMipMapped::kNo,
-                                                               *backendTexHandle);
+                                          GrBackendTexture* backendTex) {
+    *backendTex = context->getGpu()->createTestingOnlyBackendTexture(nullptr, p.fSize, p.fSize,
+                                                                     p.fConfig, false,
+                                                                     GrMipMapped::kNo);
 
-    sk_sp<GrSurface> tex = context->resourceProvider()->wrapBackendTexture(backendTex,
+    sk_sp<GrSurface> tex = context->resourceProvider()->wrapBackendTexture(*backendTex,
                                                                            kBorrow_GrWrapOwnership);
     return GrSurfaceProxy::MakeWrapped(std::move(tex), p.fOrigin);
 }
 
-static void cleanup_backend(GrContext* context, GrBackendObject* backendTexHandle) {
-    context->getGpu()->deleteTestingOnlyBackendTexture(*backendTexHandle);
+static void cleanup_backend(GrContext* context, GrBackendTexture* backendTex) {
+    context->getGpu()->deleteTestingOnlyBackendTexture(backendTex);
 }
 
 // Basic test that two proxies with overlapping intervals and compatible descriptors are
@@ -195,12 +190,12 @@
             { { 64, kNotRT, kRGBA, kE, 0, kTL }, { 64, kNotRT, kRGBA, kE, 0, kTL }, kDontShare }
         };
 
-        GrBackendObject backEndObj;
-        sk_sp<GrSurfaceProxy> p1 = make_backend(ctxInfo.grContext(), t[0].fP1, &backEndObj);
+        GrBackendTexture backEndTex;
+        sk_sp<GrSurfaceProxy> p1 = make_backend(ctxInfo.grContext(), t[0].fP1, &backEndTex);
         sk_sp<GrSurfaceProxy> p2 = make_deferred(resourceProvider, t[0].fP2);
         non_overlap_test(reporter, resourceProvider,
                          std::move(p1), std::move(p2), t[0].fExpectation);
-        cleanup_backend(ctxInfo.grContext(), &backEndObj);
+        cleanup_backend(ctxInfo.grContext(), &backEndTex);
     }
 }
 
diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp
index 0d97779..d0666d5 100644
--- a/tests/ResourceCacheTest.cpp
+++ b/tests/ResourceCacheTest.cpp
@@ -201,32 +201,24 @@
         return;
     }
 
-    GrBackendObject texHandles[2];
+    GrBackendTexture backendTextures[2];
     static const int kW = 100;
     static const int kH = 100;
 
-    texHandles[0] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kRGBA_8888_GrPixelConfig);
-    texHandles[1] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kRGBA_8888_GrPixelConfig);
+    backendTextures[0] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
+                                                              kRGBA_8888_GrPixelConfig,
+                                                              false, GrMipMapped::kNo);
+    backendTextures[1] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
+                                                              kRGBA_8888_GrPixelConfig,
+                                                              false, GrMipMapped::kNo);
 
     context->resetContext();
 
-    GrBackendTexture backendTex1 = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                                kW,
-                                                                kH,
-                                                                kRGBA_8888_GrPixelConfig,
-                                                                GrMipMapped::kNo,
-                                                                texHandles[0]);
     sk_sp<GrTexture> borrowed(context->resourceProvider()->wrapBackendTexture(
-            backendTex1, kBorrow_GrWrapOwnership));
+            backendTextures[0], kBorrow_GrWrapOwnership));
 
-    GrBackendTexture backendTex2 = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                                kW,
-                                                                kH,
-                                                                kRGBA_8888_GrPixelConfig,
-                                                                GrMipMapped::kNo,
-                                                                texHandles[1]);
     sk_sp<GrTexture> adopted(context->resourceProvider()->wrapBackendTexture(
-            backendTex2, kAdopt_GrWrapOwnership));
+            backendTextures[1], kAdopt_GrWrapOwnership));
 
     REPORTER_ASSERT(reporter, borrowed != nullptr && adopted != nullptr);
     if (!borrowed || !adopted) {
@@ -238,14 +230,14 @@
 
     context->flush();
 
-    bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(texHandles[0]);
-    bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(texHandles[1]);
+    bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[0]);
+    bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[1]);
 
     REPORTER_ASSERT(reporter, borrowedIsAlive);
     REPORTER_ASSERT(reporter, !adoptedIsAlive);
 
-    gpu->deleteTestingOnlyBackendTexture(texHandles[0], !borrowedIsAlive);
-    gpu->deleteTestingOnlyBackendTexture(texHandles[1], !adoptedIsAlive);
+    gpu->deleteTestingOnlyBackendTexture(&(backendTextures[0]), !borrowedIsAlive);
+    gpu->deleteTestingOnlyBackendTexture(&(backendTextures[1]), !adoptedIsAlive);
 
     context->resetContext();
 }
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index bcd9e2d..ac1acec 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -583,57 +583,50 @@
 
 #if SK_SUPPORT_GPU
 static sk_sp<SkSurface> create_gpu_surface_backend_texture(
-    GrContext* context, int sampleCnt, uint32_t color, GrBackendObject* outTexture) {
+    GrContext* context, int sampleCnt, uint32_t color, GrBackendTexture* outTexture) {
     const int kWidth = 10;
     const int kHeight = 10;
     std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]);
     sk_memset32(pixels.get(), color, kWidth * kHeight);
 
-    GrBackendObject backendHandle = context->getGpu()->createTestingOnlyBackendTexture(
-        pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true);
+    *outTexture = context->getGpu()->createTestingOnlyBackendTexture(
+        pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
 
-    GrBackendTexture backendTex = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                               kWidth,
-                                                               kHeight,
-                                                               kRGBA_8888_GrPixelConfig,
-                                                               GrMipMapped::kNo,
-                                                               backendHandle);
+    if (!context->getGpu()->isTestingOnlyBackendTexture(*outTexture)) {
+        return nullptr;
+    }
 
-    sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, backendTex,
+    sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, *outTexture,
                                                                  kTopLeft_GrSurfaceOrigin, sampleCnt,
                                                                  nullptr, nullptr);
     if (!surface) {
-        context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+        context->getGpu()->deleteTestingOnlyBackendTexture(outTexture);
         return nullptr;
     }
-    *outTexture = backendHandle;
     return surface;
 }
 
 static sk_sp<SkSurface> create_gpu_surface_backend_texture_as_render_target(
-    GrContext* context, int sampleCnt, uint32_t color, GrBackendObject* outTexture) {
+    GrContext* context, int sampleCnt, uint32_t color, GrBackendTexture* outTexture) {
     const int kWidth = 10;
     const int kHeight = 10;
     std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]);
     sk_memset32(pixels.get(), color, kWidth * kHeight);
 
-    GrBackendObject backendHandle = context->getGpu()->createTestingOnlyBackendTexture(
-        pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true);
+    *outTexture = context->getGpu()->createTestingOnlyBackendTexture(
+        pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
 
-    GrBackendTexture backendTex = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                               kWidth,
-                                                               kHeight,
-                                                               kRGBA_8888_GrPixelConfig,
-                                                               GrMipMapped::kNo,
-                                                               backendHandle);
-    sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
-            context, backendTex, kTopLeft_GrSurfaceOrigin, sampleCnt, nullptr, nullptr);
-
-    if (!surface) {
-        context->getGpu()->deleteTestingOnlyBackendTexture(backendHandle);
+    if (!context->getGpu()->isTestingOnlyBackendTexture(*outTexture)) {
         return nullptr;
     }
-    *outTexture = backendHandle;
+
+    sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
+            context, *outTexture, kTopLeft_GrSurfaceOrigin, sampleCnt, nullptr, nullptr);
+
+    if (!surface) {
+        context->getGpu()->deleteTestingOnlyBackendTexture(outTexture);
+        return nullptr;
+    }
     return surface;
 }
 
@@ -704,11 +697,11 @@
         const uint32_t kOrigColor = 0xABABABAB;
         for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
                                   &create_gpu_surface_backend_texture_as_render_target}) {
-            GrBackendObject textureObject;
-            auto surface = surfaceFunc(context, 0, kOrigColor, &textureObject);
+            GrBackendTexture backendTex;
+            auto surface = surfaceFunc(context, 0, kOrigColor, &backendTex);
             test_surface_clear(reporter, surface, grSurfaceGetter, kOrigColor);
             surface.reset();
-            context->getGpu()->deleteTestingOnlyBackendTexture(textureObject);
+            context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }
@@ -767,12 +760,12 @@
         // Validate that we can draw to the canvas and that the original texture color is
         // preserved in pixels that aren't rendered to via the surface.
         // This works only for non-multisampled case.
-        GrBackendObject textureObject;
-        auto surface = surfaceFunc(ctxInfo.grContext(), 0, kOrigColor, &textureObject);
+        GrBackendTexture backendTex;
+        auto surface = surfaceFunc(ctxInfo.grContext(), 0, kOrigColor, &backendTex);
         if (surface) {
             test_surface_draw_partially(reporter, surface, kOrigColor);
             surface.reset();
-            gpu->deleteTestingOnlyBackendTexture(textureObject);
+            gpu->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }
@@ -791,12 +784,12 @@
     for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
                               &create_gpu_surface_backend_texture_as_render_target}) {
         for (int sampleCnt : {0, 4, 8}) {
-            GrBackendObject textureObject;
-            auto surface = surfaceFunc(ctxInfo.grContext(), sampleCnt, kOrigColor, &textureObject);
+            GrBackendTexture backendTex;
+            auto surface = surfaceFunc(ctxInfo.grContext(), sampleCnt, kOrigColor, &backendTex);
 
             if (!surface && sampleCnt > 0) {
-              // Certain platforms don't support MSAA, skip these.
-              continue;
+                // Certain platforms don't support MSAA, skip these.
+                continue;
             }
 
             // Validate that we can attach a stencil buffer to an SkSurface created by either of
@@ -805,7 +798,7 @@
                 ->internal_private_accessTopLayerRenderTargetContext()->accessRenderTarget();
             REPORTER_ASSERT(reporter,
                             ctxInfo.grContext()->resourceProvider()->attachStencilAttachment(rt));
-            gpu->deleteTestingOnlyBackendTexture(textureObject);
+            gpu->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }
@@ -889,25 +882,18 @@
 
     test_surface_creation_and_snapshot_with_color_space(reporter, "gpu", f16Support, surfaceMaker);
 
-    std::vector<GrBackendObject> textureHandles;
-    auto wrappedSurfaceMaker = [context,&textureHandles](const SkImageInfo& info) {
+    std::vector<GrBackendTexture> backendTextures;
+    auto wrappedSurfaceMaker = [ context, &backendTextures ](const SkImageInfo& info) {
         static const int kSize = 10;
         GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *context->caps());
 
-        GrBackendObject backendHandle = context->getGpu()->createTestingOnlyBackendTexture(
-                nullptr, kSize, kSize, config, true);
+        GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture(
+                nullptr, kSize, kSize, config, true, GrMipMapped::kNo);
 
-        if (!backendHandle) {
+        if (!context->getGpu()->isTestingOnlyBackendTexture(backendTex)) {
             return sk_sp<SkSurface>(nullptr);
         }
-        textureHandles.push_back(backendHandle);
-
-        GrBackendTexture backendTex = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
-                                                                   kSize,
-                                                                   kSize,
-                                                                   config,
-                                                                   GrMipMapped::kNo,
-                                                                   backendHandle);
+        backendTextures.push_back(backendTex);
 
         return SkSurface::MakeFromBackendTexture(context, backendTex,
                                                  kTopLeft_GrSurfaceOrigin, 0,
@@ -919,8 +905,8 @@
 
     context->flush();
 
-    for (auto textureHandle : textureHandles) {
-        context->getGpu()->deleteTestingOnlyBackendTexture(textureHandle);
+    for (auto backendTex : backendTextures) {
+        context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
     }
 }
 #endif
diff --git a/tests/VkWrapTests.cpp b/tests/VkWrapTests.cpp
index 07b82a8..cf28586 100644
--- a/tests/VkWrapTests.cpp
+++ b/tests/VkWrapTests.cpp
@@ -32,110 +32,128 @@
 
     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->getGpu());
 
-    GrBackendObject backendObj = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kPixelConfig,
-                                                                      false, GrMipMapped::kNo);
-    const GrVkImageInfo* imageInfo = reinterpret_cast<const GrVkImageInfo*>(backendObj);
+    GrBackendTexture origBackendTex = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
+                                                                           kPixelConfig, false,
+                                                                           GrMipMapped::kNo);
+    const GrVkImageInfo* imageInfo = origBackendTex.getVkImageInfo();
 
-    GrBackendTexture backendTex = GrBackendTexture(kW, kH, *imageInfo);
-    sk_sp<GrTexture> tex = gpu->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership);
+    sk_sp<GrTexture> tex = gpu->wrapBackendTexture(origBackendTex, kBorrow_GrWrapOwnership);
     REPORTER_ASSERT(reporter, tex);
 
     // image is null
-    GrVkImageInfo backendCopy = *imageInfo;
-    backendCopy.fImage = VK_NULL_HANDLE;
-    backendTex = GrBackendTexture(kW, kH, backendCopy);
-    tex = gpu->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
-    tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        backendCopy.fImage = VK_NULL_HANDLE;
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+        tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+    }
 
     // alloc is null
-    backendCopy.fImage = imageInfo->fImage;
-    backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
-    backendTex = GrBackendTexture(kW, kH, backendCopy);
-    tex = gpu->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
-    tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+        tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+    }
+
     // check adopt creation
-    backendCopy.fAlloc = imageInfo->fAlloc;
-    backendTex = GrBackendTexture(kW, kH, backendCopy);
-    tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership);
 
-    REPORTER_ASSERT(reporter, tex);
+        REPORTER_ASSERT(reporter, tex);
+    }
 
-    gpu->deleteTestingOnlyBackendTexture(backendObj, true);
+    gpu->deleteTestingOnlyBackendTexture(&origBackendTex, true);
 }
 
 void wrap_rt_test(skiatest::Reporter* reporter, GrContext* context) {
     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->getGpu());
 
-    GrBackendObject backendObj = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kPixelConfig,
-                                                                      true, GrMipMapped::kNo);
-    const GrVkImageInfo* backendTex = reinterpret_cast<const GrVkImageInfo*>(backendObj);
+    GrBackendTexture origBackendTex = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
+                                                                           kPixelConfig, true,
+                                                                           GrMipMapped::kNo);
+    const GrVkImageInfo* imageInfo = origBackendTex.getVkImageInfo();
 
-    GrBackendRenderTarget backendRT(kW, kH, 0, 0, *backendTex);
+    GrBackendRenderTarget origBackendRT(kW, kH, 0, 0, *imageInfo);
 
-    sk_sp<GrRenderTarget> rt = gpu->wrapBackendRenderTarget(backendRT);
+    sk_sp<GrRenderTarget> rt = gpu->wrapBackendRenderTarget(origBackendRT);
     REPORTER_ASSERT(reporter, rt);
 
     // image is null
-    GrVkImageInfo backendCopy = *backendTex;
-    backendCopy.fImage = VK_NULL_HANDLE;
-    GrBackendRenderTarget backendRT2(kW, kH, 0, 0, backendCopy);
-    rt = gpu->wrapBackendRenderTarget(backendRT2);
-    REPORTER_ASSERT(reporter, !rt);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        backendCopy.fImage = VK_NULL_HANDLE;
+        GrBackendRenderTarget backendRT(kW, kH, 0, 0, backendCopy);
+        rt = gpu->wrapBackendRenderTarget(backendRT);
+        REPORTER_ASSERT(reporter, !rt);
+    }
 
     // alloc is null
-    backendCopy.fImage = backendTex->fImage;
-    backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
-    // can wrap null alloc
-    GrBackendRenderTarget backendRT3(kW, kH, 0, 0, backendCopy);
-    rt = gpu->wrapBackendRenderTarget(backendRT3);
-    REPORTER_ASSERT(reporter, rt);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+        // can wrap null alloc
+        GrBackendRenderTarget backendRT(kW, kH, 0, 0, backendCopy);
+        rt = gpu->wrapBackendRenderTarget(backendRT);
+        REPORTER_ASSERT(reporter, rt);
+    }
 
     // When we wrapBackendRenderTarget it is always borrowed, so we must make sure to free the
     // resource when we're done.
-    gpu->deleteTestingOnlyBackendTexture(backendObj, false);
+    gpu->deleteTestingOnlyBackendTexture(&origBackendTex);
 }
 
 void wrap_trt_test(skiatest::Reporter* reporter, GrContext* context) {
     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->getGpu());
 
-    GrBackendObject backendObj = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kPixelConfig,
-                                                                      true, GrMipMapped::kNo);
-    const GrVkImageInfo* imageInfo = reinterpret_cast<const GrVkImageInfo*>(backendObj);
+    GrBackendTexture origBackendTex = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
+                                                                           kPixelConfig, true,
+                                                                           GrMipMapped::kNo);
+    const GrVkImageInfo* imageInfo = origBackendTex.getVkImageInfo();
 
-    GrBackendTexture backendTex = GrBackendTexture(kW, kH, *imageInfo);
-    sk_sp<GrTexture> tex = gpu->wrapRenderableBackendTexture(backendTex, 0,
+    sk_sp<GrTexture> tex = gpu->wrapRenderableBackendTexture(origBackendTex, 0,
                                                              kBorrow_GrWrapOwnership);
     REPORTER_ASSERT(reporter, tex);
 
     // image is null
-    GrVkImageInfo backendCopy = *imageInfo;
-    backendCopy.fImage = VK_NULL_HANDLE;
-    backendTex = GrBackendTexture(kW, kH, backendCopy);
-    tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kBorrow_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
-    tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        backendCopy.fImage = VK_NULL_HANDLE;
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kBorrow_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+    }
 
     // alloc is null
-    backendCopy.fImage = imageInfo->fImage;
-    backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
-    backendTex = GrBackendTexture(kW, kH, backendCopy);
-    tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kBorrow_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
-    tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, !tex);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kBorrow_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, !tex);
+    }
 
     // check adopt creation
-    backendCopy.fAlloc = imageInfo->fAlloc;
-    backendTex = GrBackendTexture(kW, kH, backendCopy);
-    tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
-    REPORTER_ASSERT(reporter, tex);
+    {
+        GrVkImageInfo backendCopy = *imageInfo;
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
+        REPORTER_ASSERT(reporter, tex);
+    }
 
-    gpu->deleteTestingOnlyBackendTexture(backendObj, true);
+    gpu->deleteTestingOnlyBackendTexture(&origBackendTex, true);
 }
 
 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkWrapTests, reporter, ctxInfo) {
diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp
index 364cf1a..bfa0d4d 100644
--- a/tests/WritePixelsTest.cpp
+++ b/tests/WritePixelsTest.cpp
@@ -428,22 +428,19 @@
 
     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
         for (int sampleCnt : {0, 4}) {
-            auto handle = context->getGpu()->createTestingOnlyBackendTexture(
-                    nullptr, DEV_W, DEV_H, kSkia8888_GrPixelConfig, true);
-            GrBackendTexture backendTexture = GrTest::CreateBackendTexture(
-                    ctxInfo.backend(), DEV_W, DEV_H, kSkia8888_GrPixelConfig, GrMipMapped::kNo,
-                    handle);
+            GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture(
+                    nullptr, DEV_W, DEV_H, kSkia8888_GrPixelConfig, true, GrMipMapped::kNo);
             sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(
-                    context, backendTexture, origin, sampleCnt, nullptr, nullptr));
+                    context, backendTex, origin, sampleCnt, nullptr, nullptr));
             if (!surface) {
-                context->getGpu()->deleteTestingOnlyBackendTexture(handle);
+                context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
                 continue;
             }
 
             test_write_pixels(reporter, surface.get());
 
             surface.reset();
-            context->getGpu()->deleteTestingOnlyBackendTexture(handle);
+            context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex);
         }
     }
 }