Add testing-only backend render target support to GrVkGpu.

Update unit tests to use backend render targets on non-GL contexts

Add named DM configs for rendering to Vulkan backend render targets and textures.

Make src data ptr param to createTestingOnlyBackendTexture be const.

Change-Id: I17f5375ed9bb08422006698956469d3151c4954c
Reviewed-on: https://skia-review.googlesource.com/113276
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 40d7664..2aacc49 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -452,14 +452,13 @@
     /** 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(). */
-    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h, SkColorType,
+    GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h, SkColorType,
                                                      bool isRenderTarget, GrMipMapped);
     /** Older version based on GrPixelConfig. Currently the preferred one above devolves to this. */
-    virtual GrBackendTexture createTestingOnlyBackendTexture(
-                                                      void* pixels, int w, int h,
-                                                      GrPixelConfig config,
-                                                      bool isRenderTarget,
-                                                      GrMipMapped mipMapped) = 0;
+    virtual GrBackendTexture createTestingOnlyBackendTexture(const 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;
     /**
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 7e69fbe..9023554 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -4345,7 +4345,7 @@
 }
 
 #if GR_TEST_UTILS
-GrBackendTexture GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
+GrBackendTexture GrGLGpu::createTestingOnlyBackendTexture(const void* pixels, int w, int h,
                                                           GrPixelConfig config, bool /*isRT*/,
                                                           GrMipMapped mipMapped) {
     if (!this->caps()->isConfigTexturable(config)) {
@@ -4395,7 +4395,7 @@
     if (!pixels) {
         // Fill in the texture with all zeros so we don't have random garbage
         pixels = defaultStorage.get();
-        memset(pixels, 0, baseLayerSize);
+        memset(defaultStorage.get(), 0, baseLayerSize);
     }
 
     int width = w;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 79d74d2..7ddd4e7 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -145,9 +145,8 @@
                                                                 int width,
                                                                 int height) override;
 #if GR_TEST_UTILS
-    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                     GrPixelConfig config,
-                                                     bool isRenderTarget,
+    GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h,
+                                                     GrPixelConfig config, bool isRenderTarget,
                                                      GrMipMapped mipMapped) override;
     bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
     void deleteTestingOnlyBackendTexture(const GrBackendTexture&) override;
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index b1c3e7d..4b786ab 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -181,7 +181,7 @@
 }
 
 #if GR_TEST_UTILS
-GrBackendTexture GrMockGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
+GrBackendTexture GrMockGpu::createTestingOnlyBackendTexture(const void* pixels, int w, int h,
                                                             GrPixelConfig config, bool isRT,
                                                             GrMipMapped mipMapped) {
     GrMockTextureInfo info;
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index f0d7c07..8a3dc30 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -114,8 +114,9 @@
     void clearStencil(GrRenderTarget*, int clearValue) override  {}
 
 #if GR_TEST_UTILS
-    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h, GrPixelConfig,
-                                                    bool isRT, GrMipMapped) override;
+    GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h,
+                                                     GrPixelConfig, bool isRT,
+                                                     GrMipMapped) override;
     bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
     void deleteTestingOnlyBackendTexture(const GrBackendTexture&) override;
 
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 1babc82..4729e6e 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -138,7 +138,7 @@
     void clearStencil(GrRenderTarget* target, int clearValue) override  {}
 
 #if GR_TEST_UTILS
-    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
+    GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h,
                                                      GrPixelConfig config, bool isRT,
                                                      GrMipMapped) override {
         return GrBackendTexture();
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 73787bf..5e6473e 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1131,8 +1131,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool copy_testing_data(GrVkGpu* gpu, void* srcData, const GrVkAlloc& alloc, size_t bufferOffset,
-                       size_t srcRowBytes, size_t dstRowBytes, int h) {
+bool copy_testing_data(GrVkGpu* gpu, const void* srcData, const GrVkAlloc& alloc,
+                       size_t bufferOffset, size_t srcRowBytes, size_t dstRowBytes, int h) {
     // For Noncoherent buffers we want to make sure the range that we map, both offset and size,
     // are aligned to the nonCoherentAtomSize limit. We may have to move the initial offset back to
     // meet the alignment requirements. So we track how far we move back and then adjust the mapped
@@ -1184,33 +1184,39 @@
 }
 
 #if GR_TEST_UTILS
-GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h,
-                                                          GrPixelConfig config,
-                                                          bool isRenderTarget,
-                                                          GrMipMapped mipMapped) {
-
+bool GrVkGpu::createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool texturable,
+                                       bool renderable, GrMipMapped mipMapped, const void* srcData,
+                                       GrVkImageInfo* info) {
+    SkASSERT(texturable || renderable);
+    if (!texturable) {
+        SkASSERT(GrMipMapped::kNo == mipMapped);
+        SkASSERT(!srcData);
+    }
     VkFormat pixelFormat;
     if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
-        return GrBackendTexture(); // invalid
+        return false;
     }
 
-    if (!fVkCaps->isConfigTexturable(config)) {
-        return GrBackendTexture(); // invalid
+    if (texturable && !fVkCaps->isConfigTexturable(config)) {
+        return false;
     }
 
-    if (isRenderTarget && !fVkCaps->isConfigRenderable(config)) {
-        return GrBackendTexture(); // invalid
+    if (renderable && !fVkCaps->isConfigRenderable(config)) {
+        return false;
     }
 
     // Currently we don't support uploading pixel data when mipped.
     if (srcData && GrMipMapped::kYes == mipMapped) {
-        return GrBackendTexture(); // invalid
+        return false;
     }
 
-    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
+    VkImageUsageFlags usageFlags = 0;
     usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
     usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-    if (isRenderTarget) {
+    if (texturable) {
+        usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
+    }
+    if (renderable) {
         usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
     }
 
@@ -1221,7 +1227,7 @@
     // Create Image
     VkSampleCountFlagBits vkSamples;
     if (!GrSampleCountToVkSampleCount(1, &vkSamples)) {
-        return GrBackendTexture(); // invalid
+        return false;
     }
 
     // Figure out the number of mip levels.
@@ -1248,11 +1254,12 @@
             initialLayout                         // initialLayout
     };
 
-    GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateImage(this->device(), &imageCreateInfo, nullptr, &image));
+    GR_VK_CALL_ERRCHECK(this->vkInterface(),
+                        CreateImage(this->device(), &imageCreateInfo, nullptr, &image));
 
     if (!GrVkMemory::AllocAndBindImageMemory(this, image, false, &alloc)) {
         VK_CALL(DestroyImage(this->device(), image, nullptr));
-        return GrBackendTexture(); // invalid
+        return false;
     }
 
     // We need to declare these early so that we can delete them at the end outside of the if block.
@@ -1273,7 +1280,7 @@
     if (err) {
         GrVkMemory::FreeImageMemory(this, false, alloc);
         VK_CALL(DestroyImage(fDevice, image, nullptr));
-        return GrBackendTexture(); // invalid
+        return false;
     }
 
     VkCommandBufferBeginInfo cmdBufferBeginInfo;
@@ -1328,7 +1335,7 @@
         VK_CALL(DestroyImage(fDevice, image, nullptr));
         VK_CALL(EndCommandBuffer(cmdBuffer));
         VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
-        return GrBackendTexture();  // invalid
+        return false;
     }
 
     if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, true,
@@ -1338,7 +1345,7 @@
         VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
         VK_CALL(EndCommandBuffer(cmdBuffer));
         VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
-        return GrBackendTexture();  // invalid
+        return false;
     }
 
     currentWidth = w;
@@ -1355,7 +1362,7 @@
             VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
             VK_CALL(EndCommandBuffer(cmdBuffer));
             VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
-            return GrBackendTexture(); // invalid
+            return false;
         }
         currentWidth = SkTMax(1, currentWidth / 2);
         currentHeight = SkTMax(1, currentHeight / 2);
@@ -1401,27 +1408,29 @@
     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
-    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));
+    if (texturable) {
+        // 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
+        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};
+        initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+        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));
@@ -1471,15 +1480,24 @@
     VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer));
     VK_CALL(DestroyFence(fDevice, fence, nullptr));
 
+    info->fImage = image;
+    info->fAlloc = alloc;
+    info->fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+    info->fImageLayout = initialLayout;
+    info->fFormat = pixelFormat;
+    info->fLevelCount = mipLevels;
 
+    return true;
+}
+
+GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(const void* srcData, int w, int h,
+                                                          GrPixelConfig config, bool isRenderTarget,
+                                                          GrMipMapped mipMapped) {
     GrVkImageInfo info;
-    info.fImage = image;
-    info.fAlloc = alloc;
-    info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
-    info.fImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-    info.fFormat = pixelFormat;
-    info.fLevelCount = mipLevels;
-
+    if (!this->createTestingOnlyVkImage(config, w, h, true, isRenderTarget, mipMapped, srcData,
+                                        &info)) {
+        return {};
+    }
     return GrBackendTexture(w, h, info);
 }
 
@@ -1512,13 +1530,29 @@
     }
 }
 
-GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType,
-                                                                    GrSRGBEncoded) {
-    return GrBackendRenderTarget();
+GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct,
+                                                                    GrSRGBEncoded srgbEncoded) {
+    GrVkImageInfo info;
+    auto config = GrColorTypeToPixelConfig(ct, srgbEncoded);
+    if (kUnknown_GrPixelConfig == config) {
+        return {};
+    }
+    if (!this->createTestingOnlyVkImage(config, w, h, false, true, GrMipMapped::kNo, nullptr,
+                                        &info)) {
+        return {};
+    }
+    return {w, h, 1, 0, info};
 }
 
-void GrVkGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {}
+void GrVkGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
+    SkASSERT(kVulkan_GrBackend == rt.fBackend);
 
+    if (const auto* info = rt.getVkImageInfo()) {
+        // something in the command buffer may still be using this, so force submit
+        this->submitCommandBuffer(kForce_SyncQueue);
+        GrVkImage::DestroyImageInfo(this, const_cast<GrVkImageInfo*>(info));
+    }
+}
 
 void GrVkGpu::testingOnly_flushGpuAndSync() {
     this->submitCommandBuffer(kForce_SyncQueue);
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index b5ddcb8..6eac5c8 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -70,9 +70,8 @@
     void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
 
 #if GR_TEST_UTILS
-    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
-                                                     GrPixelConfig config,
-                                                     bool isRenderTarget,
+    GrBackendTexture createTestingOnlyBackendTexture(const void* pixels, int w, int h,
+                                                     GrPixelConfig config, bool isRenderTarget,
                                                      GrMipMapped) override;
     bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
     void deleteTestingOnlyBackendTexture(const GrBackendTexture&) override;
@@ -247,6 +246,12 @@
     void resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,
                       const SkIPoint& dstPoint);
 
+#if GR_TEST_UTILS
+    bool createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool texturable,
+                                  bool renderable, GrMipMapped mipMapped, const void* srcData,
+                                  GrVkImageInfo* info);
+#endif
+
     sk_sp<const GrVkBackendContext> fBackendContext;
     sk_sp<GrVkCaps>                 fVkCaps;
 
diff --git a/tests/ProxyConversionTest.cpp b/tests/ProxyConversionTest.cpp
index 3ebfbf4..7103403 100644
--- a/tests/ProxyConversionTest.cpp
+++ b/tests/ProxyConversionTest.cpp
@@ -12,6 +12,7 @@
 #if SK_SUPPORT_GPU
 #include "GrBackendSurface.h"
 #include "GrContextPriv.h"
+#include "GrGpu.h"
 #include "GrProxyProvider.h"
 #include "GrRenderTarget.h"
 #include "GrRenderTargetProxy.h"
@@ -19,36 +20,46 @@
 #include "GrTexture.h"
 #include "GrTextureProxy.h"
 
-static sk_sp<GrSurfaceProxy> make_wrapped_FBO0(GrProxyProvider* provider,
-                                               skiatest::Reporter* reporter,
-                                               const GrSurfaceDesc& desc,
-                                               GrSurfaceOrigin origin) {
-    GrGLFramebufferInfo fboInfo;
-    fboInfo.fFBOID = 0;
-    GrBackendRenderTarget backendRT(desc.fWidth, desc.fHeight, desc.fSampleCnt, 8,
-                                    desc.fConfig, fboInfo);
-
+static sk_sp<GrSurfaceProxy> make_wrapped_rt(GrProxyProvider* provider,
+                                             GrGpu* gpu,
+                                             skiatest::Reporter* reporter,
+                                             const GrSurfaceDesc& desc,
+                                             GrSurfaceOrigin origin) {
+    // We don't currently have a way of making MSAA backend render targets.
+    SkASSERT(1 == desc.fSampleCnt);
+    GrSRGBEncoded srgbEncoded;
+    auto ct = GrPixelConfigToColorTypeAndEncoding(desc.fConfig, &srgbEncoded);
+    auto backendRT = gpu->createTestingOnlyBackendRenderTarget(desc.fWidth, desc.fHeight, ct,
+                                                               GrSRGBEncoded::kNo);
     return provider->wrapBackendRenderTarget(backendRT, origin);
 }
 
-static sk_sp<GrSurfaceProxy> make_wrapped_offscreen_rt(GrProxyProvider* provider,
-                                                       const GrSurfaceDesc& desc,
-                                                       GrSurfaceOrigin origin) {
+void clean_up_wrapped_rt(GrGpu* gpu, sk_sp<GrSurfaceProxy> proxy) {
+    SkASSERT(proxy->isUnique_debugOnly());
+    SkASSERT(proxy->priv().peekRenderTarget());
+    GrBackendRenderTarget rt = proxy->priv().peekRenderTarget()->getBackendRenderTarget();
+    proxy.reset();
+    gpu->deleteTestingOnlyBackendRenderTarget(rt);
+}
+
+static sk_sp<GrSurfaceProxy> make_offscreen_rt(GrProxyProvider* provider,
+                                               const GrSurfaceDesc& desc,
+                                               GrSurfaceOrigin origin) {
     SkASSERT(kRenderTarget_GrSurfaceFlag == desc.fFlags);
 
     return provider->createInstantiatedProxy(desc, origin, SkBackingFit::kExact, SkBudgeted::kYes);
 }
 
-static sk_sp<GrSurfaceProxy> make_wrapped_texture(GrProxyProvider* provider,
-                                                  const GrSurfaceDesc& desc,
-                                                  GrSurfaceOrigin origin) {
+static sk_sp<GrSurfaceProxy> make_texture(GrProxyProvider* provider,
+                                          const GrSurfaceDesc& desc,
+                                          GrSurfaceOrigin origin) {
     return provider->createInstantiatedProxy(desc, origin, SkBackingFit::kExact, SkBudgeted::kYes);
 }
 
-// Test converting between RenderTargetProxies and TextureProxies for wrapped
-// Proxies
-DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WrappedProxyConversionTest, reporter, ctxInfo) {
+// Test converting between RenderTargetProxies and TextureProxies for preinstantiated Proxies
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PreinstantiatedProxyConversionTest, reporter, ctxInfo) {
     GrProxyProvider* proxyProvider = ctxInfo.grContext()->contextPriv().proxyProvider();
+    GrGpu* gpu = ctxInfo.grContext()->contextPriv().getGpu();
 
     GrSurfaceDesc desc;
     desc.fFlags = kRenderTarget_GrSurfaceFlag;
@@ -56,23 +67,24 @@
     desc.fHeight = 64;
     desc.fConfig = kRGBA_8888_GrPixelConfig;
 
-    if (kOpenGL_GrBackend == ctxInfo.backend()) {
+    {
         // External on-screen render target.
         sk_sp<GrSurfaceProxy> sProxy(
-                make_wrapped_FBO0(proxyProvider, reporter, desc, kBottomLeft_GrSurfaceOrigin));
+                make_wrapped_rt(proxyProvider, gpu, reporter, desc, kBottomLeft_GrSurfaceOrigin));
         if (sProxy) {
             // RenderTarget-only
             GrRenderTargetProxy* rtProxy = sProxy->asRenderTargetProxy();
             REPORTER_ASSERT(reporter, rtProxy);
             REPORTER_ASSERT(reporter, !rtProxy->asTextureProxy());
             REPORTER_ASSERT(reporter, rtProxy->asRenderTargetProxy() == rtProxy);
+            clean_up_wrapped_rt(gpu, std::move(sProxy));
         }
     }
 
     {
         // Internal offscreen render target.
         sk_sp<GrSurfaceProxy> sProxy(
-                make_wrapped_offscreen_rt(proxyProvider, desc, kBottomLeft_GrSurfaceOrigin));
+                make_offscreen_rt(proxyProvider, desc, kBottomLeft_GrSurfaceOrigin));
         if (sProxy) {
             // Both RenderTarget and Texture
             GrRenderTargetProxy* rtProxy = sProxy->asRenderTargetProxy();
@@ -87,7 +99,7 @@
     {
         // Internal offscreen render target - but through GrTextureProxy
         sk_sp<GrSurfaceProxy> sProxy(
-                make_wrapped_texture(proxyProvider, desc, kBottomLeft_GrSurfaceOrigin));
+                make_texture(proxyProvider, desc, kBottomLeft_GrSurfaceOrigin));
         if (sProxy) {
             // Both RenderTarget and Texture
             GrTextureProxy* tProxy = sProxy->asTextureProxy();
@@ -103,7 +115,7 @@
         desc.fFlags = kNone_GrSurfaceFlags; // force no-RT
 
         sk_sp<GrSurfaceProxy> sProxy(
-                make_wrapped_texture(proxyProvider, desc, kBottomLeft_GrSurfaceOrigin));
+                make_texture(proxyProvider, desc, kBottomLeft_GrSurfaceOrigin));
         if (sProxy) {
             // Texture-only
             GrTextureProxy* tProxy = sProxy->asTextureProxy();
diff --git a/tests/ProxyTest.cpp b/tests/ProxyTest.cpp
index 911c430..4970e43 100644
--- a/tests/ProxyTest.cpp
+++ b/tests/ProxyTest.cpp
@@ -201,12 +201,28 @@
 
     static const int kWidthHeight = 100;
 
-    if (kOpenGL_GrBackend != ctxInfo.backend()) {
-        return;
-    }
     for (auto origin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
         for (auto colorType : { kAlpha_8_SkColorType, kRGBA_8888_SkColorType,
                                 kRGBA_1010102_SkColorType }) {
+            // External on-screen render target.
+            // Tests wrapBackendRenderTarget with a GrBackendRenderTarget
+            // Our test-only function that creates a backend render target doesn't currently support
+            // sample counts :(.
+            if (ctxInfo.grContext()->colorTypeSupportedAsSurface(colorType)) {
+                GrBackendRenderTarget backendRT = gpu->createTestingOnlyBackendRenderTarget(
+                        kWidthHeight, kWidthHeight, SkColorTypeToGrColorType(colorType),
+                        GrSRGBEncoded::kNo);
+                sk_sp<GrSurfaceProxy> sProxy(
+                        proxyProvider->wrapBackendRenderTarget(backendRT, origin));
+                check_surface(reporter, sProxy.get(), origin, kWidthHeight, kWidthHeight,
+                              backendRT.testingOnly_getPixelConfig(), SkBudgeted::kNo);
+                static constexpr int kExpectedNumSamples = 1;
+                check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
+                                   kExpectedNumSamples, SkBackingFit::kExact,
+                                   caps.maxWindowRectangles());
+                gpu->deleteTestingOnlyBackendRenderTarget(backendRT);
+            }
+
             for (auto numSamples : {1, 4}) {
                 GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, caps);
                 SkASSERT(kUnknown_GrPixelConfig != config);
@@ -216,14 +232,14 @@
                     continue;
                 }
 
-                // External on-screen render target.
-                // Tests wrapBackendRenderTarget with a GrBackendRenderTarget
-                {
+                // Test wrapping FBO 0 (with made up properties). This tests sample count and the
+                // special case where FBO 0 doesn't support window rectangles.
+                if (kOpenGL_GrBackend == ctxInfo.backend()) {
                     GrGLFramebufferInfo fboInfo;
                     fboInfo.fFBOID = 0;
-                    GrBackendRenderTarget backendRT(kWidthHeight, kWidthHeight, numSamples, 8,
-                                                    config, fboInfo);
-
+                    static constexpr int kStencilBits = 8;
+                    GrBackendRenderTarget backendRT(kWidthHeight, kWidthHeight, numSamples,
+                                                    kStencilBits, config, fboInfo);
                     sk_sp<GrSurfaceProxy> sProxy(
                             proxyProvider->wrapBackendRenderTarget(backendRT, origin));
                     check_surface(reporter, sProxy.get(), origin,
diff --git a/tools/flags/SkCommonFlagsConfig.cpp b/tools/flags/SkCommonFlagsConfig.cpp
index bb53c2d..b8fd419 100644
--- a/tools/flags/SkCommonFlagsConfig.cpp
+++ b/tools/flags/SkCommonFlagsConfig.cpp
@@ -89,6 +89,8 @@
     ,{ "vkwide",               "gpu", "api=vulkan,color=f16_wide" }
     ,{ "vkmsaa4",              "gpu", "api=vulkan,samples=4" }
     ,{ "vkmsaa8",              "gpu", "api=vulkan,samples=8" }
+    ,{ "vkbetex",              "gpu", "api=vulkan,surf=betex" }
+    ,{ "vkbert",               "gpu", "api=vulkan,surf=bert" }
 #endif
 #ifdef SK_METAL
     ,{ "mtl",                   "gpu", "api=metal" }
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index e33e2dd..e1a7924 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -212,7 +212,7 @@
 
 #endif
 
-GrBackendTexture GrGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
+GrBackendTexture GrGpu::createTestingOnlyBackendTexture(const void* pixels, int w, int h,
                                                         SkColorType colorType, bool isRenderTarget,
                                                         GrMipMapped mipMapped) {
     GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());