Revert "Make GrVkBackendContext no longer derive from SkRefCnt."

This reverts commit 93ae2337732bf206e6ef4faecc6b30c3881e8359.

Reason for revert: <INSERT REASONING HERE>

Original change's description:
> Make GrVkBackendContext no longer derive from SkRefCnt.
> 
> Also moves the helper Create functions to VkTestUtils since no clients
> are using them anymore.
> 
> Bug: skia:
> Change-Id: I7e8e4912e7ef6fb00a7e2a00407aed5e83211799
> Reviewed-on: https://skia-review.googlesource.com/135323
> Reviewed-by: Jim Van Verth <jvanverth@google.com>
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Greg Daniel <egdaniel@google.com>

TBR=egdaniel@google.com,jvanverth@google.com,bsalomon@google.com

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: skia:
Change-Id: If7201917631dc22753ea3fa6e9d2984463e38e4c
Reviewed-on: https://skia-review.googlesource.com/137903
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index aac5640..7e5dd62 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -543,6 +543,7 @@
   "$_include/private/GrVkTypesPriv.h",
   "$_src/gpu/vk/GrVkAMDMemoryAllocator.cpp",
   "$_src/gpu/vk/GrVkAMDMemoryAllocator.h",
+  "$_src/gpu/vk/GrVkBackendContext.cpp",
   "$_src/gpu/vk/GrVkBuffer.cpp",
   "$_src/gpu/vk/GrVkBuffer.h",
   "$_src/gpu/vk/GrVkBufferView.cpp",
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index c1804e0..565a3d5 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -71,6 +71,10 @@
 #ifdef SK_VULKAN
     static sk_sp<GrContext> MakeVulkan(const GrVkBackendContext&, const GrContextOptions&);
     static sk_sp<GrContext> MakeVulkan(const GrVkBackendContext&);
+    // These calls that take an sk_sp GrVkBackendContext are deprecated. Use the previous calls and
+    // set fOwnsInstanceAndDevice to false on the GrVkBackendContext.
+    static sk_sp<GrContext> MakeVulkan(sk_sp<const GrVkBackendContext>, const GrContextOptions&);
+    static sk_sp<GrContext> MakeVulkan(sk_sp<const GrVkBackendContext>);
 #endif
 
 #ifdef SK_METAL
diff --git a/include/gpu/vk/GrVkBackendContext.h b/include/gpu/vk/GrVkBackendContext.h
index fe018e4..e68e279 100644
--- a/include/gpu/vk/GrVkBackendContext.h
+++ b/include/gpu/vk/GrVkBackendContext.h
@@ -34,11 +34,9 @@
 // is that the client will set these up and pass them to the GrVkGpu constructor. The VkDevice
 // created must support at least one graphics queue, which is passed in as well.
 // The QueueFamilyIndex must match the family of the given queue. It is needed for CommandPool
-// creation, and any GrBackendObjects handed to us (e.g., for wrapped textures) needs to be created
-// in or transitioned to that family. The refs held by members of this struct must be released
-// (either by deleting the struct or manually releasing the refs) before the underlying vulkan
-// device and instance are destroyed.
-struct SK_API GrVkBackendContext {
+// creation, and any GrBackendObjects handed to us (e.g., for wrapped textures) need to be created
+// in or transitioned to that family.
+struct SK_API GrVkBackendContext : public SkRefCnt {
     VkInstance                 fInstance;
     VkPhysicalDevice           fPhysicalDevice;
     VkDevice                   fDevice;
@@ -50,9 +48,50 @@
     sk_sp<const GrVkInterface> fInterface;
     sk_sp<GrVkMemoryAllocator> fMemoryAllocator;
 
-    // This is deprecated and should be set to false. The client is responsible for managing the
-    // lifetime of the VkInstance and VkDevice objects.
-    bool                       fOwnsInstanceAndDevice = false;
+    /**
+     * Controls whether this object destroys the instance and device upon destruction. The default
+     * is temporarily 'true' to avoid breaking existing clients but will be changed to 'false'.
+     */
+    bool                       fOwnsInstanceAndDevice = true;
+
+#if GR_TEST_UTILS || defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
+    using CanPresentFn = std::function<bool(VkInstance, VkPhysicalDevice,
+                                            uint32_t queueFamilyIndex)>;
+
+    /**
+     * Helper function to create the Vulkan objects needed for a Vulkan-backed GrContext.
+     * Note that the version that uses the unified "GetProc" instead of separate "GetInstanceProc"
+     * and "GetDeviceProc" functions will be removed.
+     *
+     * If presentQueueIndex is non-NULL, will try to set up presentQueue as part of device
+     * creation using the platform-specific canPresent() function.
+     *
+     * This will set fOwnsInstanceAndDevice to 'true'. If it is subsequently set to 'false' then
+     * the client owns the lifetime of the created VkDevice and VkInstance.
+     */
+    static const GrVkBackendContext* Create(uint32_t* presentQueueIndex = nullptr,
+                                            CanPresentFn = CanPresentFn(),
+                                            GrVkInterface::GetProc getProc = nullptr);
+
+    static const GrVkBackendContext* Create(const GrVkInterface::GetInstanceProc& getInstanceProc,
+                                            const GrVkInterface::GetDeviceProc& getDeviceProc,
+                                            uint32_t* presentQueueIndex = nullptr,
+                                            CanPresentFn canPresent = CanPresentFn()) {
+        if (!getInstanceProc || !getDeviceProc) {
+            return nullptr;
+        }
+        auto getProc = [&getInstanceProc, &getDeviceProc](const char* proc_name,
+                                                          VkInstance instance, VkDevice device) {
+            if (device != VK_NULL_HANDLE) {
+                return getDeviceProc(device, proc_name);
+            }
+            return getInstanceProc(instance, proc_name);
+        };
+        return Create(presentQueueIndex, canPresent, getProc);
+    }
+#endif // GR_TEST_UTILS || defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
+
+    ~GrVkBackendContext() override;
 };
 
 #endif
diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp
index 7a054e7..d0406dd 100644
--- a/src/gpu/GrDirectContext.cpp
+++ b/src/gpu/GrDirectContext.cpp
@@ -156,7 +156,43 @@
                                        const GrContextOptions& options) {
     sk_sp<GrContext> context(new GrDirectContext(kVulkan_GrBackend));
 
-    context->fGpu = GrVkGpu::Make(backendContext, options, context.get());
+    sk_sp<GrVkBackendContext> backendContextRef(new GrVkBackendContext());
+    backendContextRef->fInstance = backendContext.fInstance;
+    backendContextRef->fPhysicalDevice = backendContext.fPhysicalDevice;
+    backendContextRef->fDevice = backendContext.fDevice;
+    backendContextRef->fQueue = backendContext.fQueue;
+    backendContextRef->fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
+    backendContextRef->fMinAPIVersion = backendContext.fMinAPIVersion;
+    backendContextRef->fExtensions = backendContext.fExtensions;
+    backendContextRef->fFeatures = backendContext.fFeatures;
+    backendContextRef->fInterface = backendContext.fInterface;
+    backendContextRef->fMemoryAllocator = backendContext.fMemoryAllocator;
+
+    SkASSERT(!backendContext.fOwnsInstanceAndDevice);
+    backendContextRef->fOwnsInstanceAndDevice = false;
+
+    context->fGpu = GrVkGpu::Make(std::move(backendContextRef), options, context.get());
+    if (!context->fGpu) {
+        return nullptr;
+    }
+
+    context->fCaps = context->fGpu->refCaps();
+    if (!context->init(options)) {
+        return nullptr;
+    }
+    return context;
+}
+
+sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext) {
+    GrContextOptions defaultOptions;
+    return MakeVulkan(std::move(backendContext), defaultOptions);
+}
+
+sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext,
+                                       const GrContextOptions& options) {
+    sk_sp<GrContext> context(new GrDirectContext(kVulkan_GrBackend));
+
+    context->fGpu = GrVkGpu::Make(std::move(backendContext), options, context.get());
     if (!context->fGpu) {
         return nullptr;
     }
diff --git a/src/gpu/vk/GrVkBackendContext.cpp b/src/gpu/vk/GrVkBackendContext.cpp
new file mode 100644
index 0000000..3c4e8d7
--- /dev/null
+++ b/src/gpu/vk/GrVkBackendContext.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAutoMalloc.h"
+#include "vk/GrVkBackendContext.h"
+#include "vk/GrVkExtensions.h"
+#include "vk/GrVkUtil.h"
+
+#if GR_TEST_UTILS || defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
+
+////////////////////////////////////////////////////////////////////////////////
+// Helper code to set up Vulkan context objects
+
+#ifdef SK_ENABLE_VK_LAYERS
+const char* kDebugLayerNames[] = {
+    // elements of VK_LAYER_LUNARG_standard_validation
+    "VK_LAYER_GOOGLE_threading",
+    "VK_LAYER_LUNARG_parameter_validation",
+    "VK_LAYER_LUNARG_object_tracker",
+    "VK_LAYER_LUNARG_image",
+    "VK_LAYER_LUNARG_core_validation",
+    "VK_LAYER_LUNARG_swapchain",
+    "VK_LAYER_GOOGLE_unique_objects",
+    // not included in standard_validation
+    //"VK_LAYER_LUNARG_api_dump",
+    //"VK_LAYER_LUNARG_vktrace",
+    //"VK_LAYER_LUNARG_screenshot",
+};
+#endif
+
+// the minimum version of Vulkan supported
+#ifdef SK_BUILD_FOR_ANDROID
+const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3);
+#else
+const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 8);
+#endif
+
+#define ACQUIRE_VK_PROC(name, instance, device)                                \
+    PFN_vk##name grVk##name =                                                  \
+        reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
+    if (grVk##name == nullptr) {                                               \
+        SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
+        return nullptr;                                                        \
+    }
+
+// Create the base Vulkan objects needed by the GrVkGpu object
+const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr,
+                                                     CanPresentFn canPresent,
+                                                     GrVkInterface::GetProc getProc) {
+    if (!getProc) {
+        return nullptr;
+    }
+    SkASSERT(getProc);
+
+    VkPhysicalDevice physDev;
+    VkDevice device;
+    VkInstance inst;
+    VkResult err;
+
+    const VkApplicationInfo app_info = {
+        VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
+        nullptr,                            // pNext
+        "vktest",                           // pApplicationName
+        0,                                  // applicationVersion
+        "vktest",                           // pEngineName
+        0,                                  // engineVerison
+        kGrVkMinimumVersion,                // apiVersion
+    };
+
+    GrVkExtensions extensions(getProc);
+    extensions.initInstance(kGrVkMinimumVersion);
+
+    SkTArray<const char*> instanceLayerNames;
+    SkTArray<const char*> instanceExtensionNames;
+    uint32_t extensionFlags = 0;
+#ifdef SK_ENABLE_VK_LAYERS
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
+        if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
+            instanceLayerNames.push_back(kDebugLayerNames[i]);
+        }
+    }
+    if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
+        instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
+        extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
+    }
+#endif
+
+    if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
+        instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
+        extensionFlags |= kKHR_surface_GrVkExtensionFlag;
+    }
+    if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+        instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+        extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
+    }
+#ifdef SK_BUILD_FOR_WIN
+    if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
+        instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
+        extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
+    }
+#elif defined(SK_BUILD_FOR_ANDROID)
+    if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
+        instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
+        extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
+    }
+#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
+    if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
+        instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
+        extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
+    }
+#endif
+
+    const VkInstanceCreateInfo instance_create = {
+        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
+        nullptr,                                   // pNext
+        0,                                         // flags
+        &app_info,                                 // pApplicationInfo
+        (uint32_t) instanceLayerNames.count(),     // enabledLayerNameCount
+        instanceLayerNames.begin(),                // ppEnabledLayerNames
+        (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
+        instanceExtensionNames.begin(),            // ppEnabledExtensionNames
+    };
+
+    ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    err = grVkCreateInstance(&instance_create, nullptr, &inst);
+    if (err < 0) {
+        SkDebugf("vkCreateInstance failed: %d\n", err);
+        return nullptr;
+    }
+
+    ACQUIRE_VK_PROC(DestroyInstance, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
+
+    uint32_t gpuCount;
+    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
+    if (err) {
+        SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+    if (!gpuCount) {
+        SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+    // Just returning the first physical device instead of getting the whole array.
+    // TODO: find best match for our needs
+    gpuCount = 1;
+    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
+    // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
+    if (err && VK_INCOMPLETE != err) {
+        SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+
+    // query to get the initial queue props size
+    uint32_t queueCount;
+    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
+    if (!queueCount) {
+        SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+
+    SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
+    // now get the actual queue props
+    VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
+
+    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
+
+    // iterate to find the graphics queue
+    uint32_t graphicsQueueIndex = queueCount;
+    for (uint32_t i = 0; i < queueCount; i++) {
+        if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+            graphicsQueueIndex = i;
+            break;
+        }
+    }
+    if (graphicsQueueIndex == queueCount) {
+        SkDebugf("Could not find any supported graphics queues.\n");
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+
+    // iterate to find the present queue, if needed
+    uint32_t presentQueueIndex = queueCount;
+    if (presentQueueIndexPtr && canPresent) {
+        for (uint32_t i = 0; i < queueCount; i++) {
+            if (canPresent(inst, physDev, i)) {
+                presentQueueIndex = i;
+                break;
+            }
+        }
+        if (presentQueueIndex == queueCount) {
+            SkDebugf("Could not find any supported present queues.\n");
+            grVkDestroyInstance(inst, nullptr);
+            return nullptr;
+        }
+        *presentQueueIndexPtr = presentQueueIndex;
+    } else {
+        // Just setting this so we end up make a single queue for graphics since there was no
+        // request for a present queue.
+        presentQueueIndex = graphicsQueueIndex;
+    }
+
+    extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
+
+    SkTArray<const char*> deviceLayerNames;
+    SkTArray<const char*> deviceExtensionNames;
+#ifdef SK_ENABLE_VK_LAYERS
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
+        if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
+            deviceLayerNames.push_back(kDebugLayerNames[i]);
+        }
+    }
+#endif
+    if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+        deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+        extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
+    }
+    if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
+        deviceExtensionNames.push_back("VK_NV_glsl_shader");
+        extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
+    }
+
+    // query to get the physical device properties
+    VkPhysicalDeviceFeatures deviceFeatures;
+    grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
+    // this looks like it would slow things down,
+    // and we can't depend on it on all platforms
+    deviceFeatures.robustBufferAccess = VK_FALSE;
+
+    uint32_t featureFlags = 0;
+    if (deviceFeatures.geometryShader) {
+        featureFlags |= kGeometryShader_GrVkFeatureFlag;
+    }
+    if (deviceFeatures.dualSrcBlend) {
+        featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
+    }
+    if (deviceFeatures.sampleRateShading) {
+        featureFlags |= kSampleRateShading_GrVkFeatureFlag;
+    }
+
+    float queuePriorities[1] = { 0.0 };
+    // Here we assume no need for swapchain queue
+    // If one is needed, the client will need its own setup code
+    const VkDeviceQueueCreateInfo queueInfo[2] = {
+        {
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+            nullptr,                                    // pNext
+            0,                                          // VkDeviceQueueCreateFlags
+            graphicsQueueIndex,                         // queueFamilyIndex
+            1,                                          // queueCount
+            queuePriorities,                            // pQueuePriorities
+        },
+        {
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+            nullptr,                                    // pNext
+            0,                                          // VkDeviceQueueCreateFlags
+            presentQueueIndex,                          // queueFamilyIndex
+            1,                                          // queueCount
+            queuePriorities,                            // pQueuePriorities
+        }
+    };
+    uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
+
+    const VkDeviceCreateInfo deviceInfo = {
+        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,    // sType
+        nullptr,                                 // pNext
+        0,                                       // VkDeviceCreateFlags
+        queueInfoCount,                          // queueCreateInfoCount
+        queueInfo,                               // pQueueCreateInfos
+        (uint32_t) deviceLayerNames.count(),     // layerCount
+        deviceLayerNames.begin(),                // ppEnabledLayerNames
+        (uint32_t) deviceExtensionNames.count(), // extensionCount
+        deviceExtensionNames.begin(),            // ppEnabledExtensionNames
+        &deviceFeatures                          // ppEnabledFeatures
+    };
+
+    err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
+    if (err) {
+        SkDebugf("CreateDevice failed: %d\n", err);
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+
+    auto interface =
+        sk_make_sp<GrVkInterface>(getProc, inst, device, extensionFlags);
+    if (!interface->validate(extensionFlags)) {
+        SkDebugf("Vulkan interface validation failed\n");
+        grVkDeviceWaitIdle(device);
+        grVkDestroyDevice(device, nullptr);
+        grVkDestroyInstance(inst, nullptr);
+        return nullptr;
+    }
+
+    VkQueue queue;
+    grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
+
+    GrVkBackendContext* ctx = new GrVkBackendContext();
+    ctx->fInstance = inst;
+    ctx->fPhysicalDevice = physDev;
+    ctx->fDevice = device;
+    ctx->fQueue = queue;
+    ctx->fGraphicsQueueIndex = graphicsQueueIndex;
+    ctx->fMinAPIVersion = kGrVkMinimumVersion;
+    ctx->fExtensions = extensionFlags;
+    ctx->fFeatures = featureFlags;
+    ctx->fInterface.reset(interface.release());
+    ctx->fOwnsInstanceAndDevice = true;
+
+    return ctx;
+}
+#endif // GR_TEST_UTILS || defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
+
+GrVkBackendContext::~GrVkBackendContext() {
+    fMemoryAllocator.reset();
+    if (fInterface == nullptr || !fOwnsInstanceAndDevice) {
+        return;
+    }
+
+    fInterface->fFunctions.fDeviceWaitIdle(fDevice);
+    fInterface->fFunctions.fDestroyDevice(fDevice, nullptr);
+    fDevice = VK_NULL_HANDLE;
+    fInterface->fFunctions.fDestroyInstance(fInstance, nullptr);
+    fInstance = VK_NULL_HANDLE;
+}
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 0b160a6..ba1f7ca 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -73,38 +73,33 @@
 }
 #endif
 
-sk_sp<GrGpu> GrVkGpu::Make(const GrVkBackendContext& backendContext,
+sk_sp<GrGpu> GrVkGpu::Make(sk_sp<const GrVkBackendContext> backendContext,
                            const GrContextOptions& options, GrContext* context) {
-    if (backendContext.fInstance == VK_NULL_HANDLE ||
-        backendContext.fPhysicalDevice == VK_NULL_HANDLE ||
-        backendContext.fDevice == VK_NULL_HANDLE ||
-        backendContext.fQueue == VK_NULL_HANDLE) {
-        return nullptr;
-    }
-    if (!backendContext.fInterface ||
-        !backendContext.fInterface->validate(backendContext.fExtensions)) {
+    if (!backendContext) {
         return nullptr;
     }
 
-    return sk_sp<GrGpu>(new GrVkGpu(context, options, backendContext));
+    if (!backendContext->fInterface->validate(backendContext->fExtensions)) {
+        return nullptr;
+    }
+
+    return sk_sp<GrGpu>(new GrVkGpu(context, options, std::move(backendContext)));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
-                 const GrVkBackendContext& backendContext)
+                 sk_sp<const GrVkBackendContext> backendCtx)
         : INHERITED(context)
-        , fInterface(std::move(backendContext.fInterface))
-        , fMemoryAllocator(backendContext.fMemoryAllocator)
-        , fInstance(backendContext.fInstance)
-        , fDevice(backendContext.fDevice)
-        , fQueue(backendContext.fQueue)
+        , fBackendContext(std::move(backendCtx))
+        , fMemoryAllocator(fBackendContext->fMemoryAllocator)
+        , fDevice(fBackendContext->fDevice)
+        , fQueue(fBackendContext->fQueue)
         , fResourceProvider(this)
         , fDisconnected(false) {
-    SkASSERT(!backendContext.fOwnsInstanceAndDevice);
 #ifdef SK_ENABLE_VK_LAYERS
     fCallback = VK_NULL_HANDLE;
-    if (backendContext.fExtensions & kEXT_debug_report_GrVkExtensionFlag) {
+    if (fBackendContext->fExtensions & kEXT_debug_report_GrVkExtensionFlag) {
         // Setup callback creation information
         VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
         callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
@@ -119,32 +114,32 @@
 
         // Register the callback
         GR_VK_CALL_ERRCHECK(this->vkInterface(),
-                            CreateDebugReportCallbackEXT(backendContext.fInstance,
+                            CreateDebugReportCallbackEXT(fBackendContext->fInstance,
                                                          &callbackCreateInfo, nullptr, &fCallback));
     }
 #endif
 
     if (!fMemoryAllocator) {
         // We were not given a memory allocator at creation
-        fMemoryAllocator.reset(new GrVkAMDMemoryAllocator(backendContext.fPhysicalDevice,
-                                                          fDevice, backendContext.fInterface));
+        fMemoryAllocator.reset(new GrVkAMDMemoryAllocator(fBackendContext->fPhysicalDevice,
+                                                          fDevice, fBackendContext->fInterface));
     }
 
     fCompiler = new SkSL::Compiler();
 
-    fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
-                               backendContext.fFeatures, backendContext.fExtensions));
+    fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), fBackendContext->fPhysicalDevice,
+                               fBackendContext->fFeatures, fBackendContext->fExtensions));
     fCaps.reset(SkRef(fVkCaps.get()));
 
-    VK_CALL(GetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &fPhysDevProps));
-    VK_CALL(GetPhysicalDeviceMemoryProperties(backendContext.fPhysicalDevice, &fPhysDevMemProps));
+    VK_CALL(GetPhysicalDeviceProperties(fBackendContext->fPhysicalDevice, &fPhysDevProps));
+    VK_CALL(GetPhysicalDeviceMemoryProperties(fBackendContext->fPhysicalDevice, &fPhysDevMemProps));
 
     const VkCommandPoolCreateInfo cmdPoolInfo = {
         VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,      // sType
         nullptr,                                         // pNext
         VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
         VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // CmdPoolCreateFlags
-        backendContext.fGraphicsQueueIndex,              // queueFamilyIndex
+        fBackendContext->fGraphicsQueueIndex,            // queueFamilyIndex
     };
     GR_VK_CALL_ERRCHECK(this->vkInterface(), CreateCommandPool(fDevice, &cmdPoolInfo, nullptr,
                                                                &fCmdPool));
@@ -206,15 +201,10 @@
 
 #ifdef SK_ENABLE_VK_LAYERS
     if (fCallback) {
-        VK_CALL(DestroyDebugReportCallbackEXT(fInstance, fCallback, nullptr));
+        VK_CALL(DestroyDebugReportCallbackEXT(fBackendContext->fInstance, fCallback, nullptr));
     }
 #endif
 
-    fMemoryAllocator.reset();
-
-    fQueue = VK_NULL_HANDLE;
-    fDevice = VK_NULL_HANDLE;
-    fInstance = VK_NULL_HANDLE;
 }
 
 GrVkGpu::~GrVkGpu() {
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index f506d28..0524760 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -38,13 +38,13 @@
 
 class GrVkGpu : public GrGpu {
 public:
-    static sk_sp<GrGpu> Make(const GrVkBackendContext&, const GrContextOptions&, GrContext*);
+    static sk_sp<GrGpu> Make(sk_sp<const GrVkBackendContext>, const GrContextOptions&, GrContext*);
 
     ~GrVkGpu() override;
 
     void disconnect(DisconnectType) override;
 
-    const GrVkInterface* vkInterface() const { return fInterface.get(); }
+    const GrVkInterface* vkInterface() const { return fBackendContext->fInterface.get(); }
     const GrVkCaps& vkCaps() const { return *fVkCaps; }
 
     GrVkMemoryAllocator* memoryAllocator() const { return fMemoryAllocator.get(); }
@@ -144,7 +144,7 @@
     bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size);
 
 private:
-    GrVkGpu(GrContext*, const GrContextOptions&, const GrVkBackendContext& backendContext);
+    GrVkGpu(GrContext*, const GrContextOptions&, sk_sp<const GrVkBackendContext> backendContext);
 
     void onResetContext(uint32_t resetBits) override {}
 
@@ -222,27 +222,28 @@
                                   GrVkImageInfo* info);
 #endif
 
-    sk_sp<const GrVkInterface>             fInterface;
-    sk_sp<GrVkMemoryAllocator>             fMemoryAllocator;
-    sk_sp<GrVkCaps>                        fVkCaps;
+    sk_sp<const GrVkBackendContext> fBackendContext;
+    sk_sp<GrVkMemoryAllocator>      fMemoryAllocator;
+    sk_sp<GrVkCaps>                 fVkCaps;
 
-    VkInstance                             fInstance;
-    VkDevice                               fDevice;
-    VkQueue                                fQueue;    // Must be Graphics queue
+    // These Vulkan objects are provided by the client, and also stored in fBackendContext.
+    // They're copied here for convenient access.
+    VkDevice                                     fDevice;
+    VkQueue                                      fQueue;    // Must be Graphics queue
 
     // Created by GrVkGpu
-    GrVkResourceProvider                   fResourceProvider;
-    VkCommandPool                          fCmdPool;
+    GrVkResourceProvider                         fResourceProvider;
+    VkCommandPool                                fCmdPool;
 
-    GrVkPrimaryCommandBuffer*              fCurrentCmdBuffer;
+    GrVkPrimaryCommandBuffer*                    fCurrentCmdBuffer;
 
-    SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToWaitOn;
-    SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToSignal;
+    SkSTArray<1, GrVkSemaphore::Resource*>       fSemaphoresToWaitOn;
+    SkSTArray<1, GrVkSemaphore::Resource*>       fSemaphoresToSignal;
 
-    VkPhysicalDeviceProperties             fPhysDevProps;
-    VkPhysicalDeviceMemoryProperties       fPhysDevMemProps;
+    VkPhysicalDeviceProperties                   fPhysDevProps;
+    VkPhysicalDeviceMemoryProperties             fPhysDevMemProps;
 
-    GrVkCopyManager                        fCopyManager;
+    GrVkCopyManager                              fCopyManager;
 
 #ifdef SK_ENABLE_VK_LAYERS
     // For reporting validation layer errors
@@ -251,11 +252,11 @@
 
     // compiler used for compiling sksl into spirv. We only want to create the compiler once since
     // there is significant overhead to the first compile of any compiler.
-    SkSL::Compiler*                        fCompiler;
+    SkSL::Compiler* fCompiler;
 
     // We need a bool to track whether or not we've already disconnected all the gpu resources from
     // vulkan context.
-    bool                                   fDisconnected;
+    bool fDisconnected;
 
     typedef GrGpu INHERITED;
 };
diff --git a/tools/gpu/vk/VkTestContext.cpp b/tools/gpu/vk/VkTestContext.cpp
index 592fb0f..25069fe 100644
--- a/tools/gpu/vk/VkTestContext.cpp
+++ b/tools/gpu/vk/VkTestContext.cpp
@@ -110,24 +110,21 @@
 class VkTestContextImpl : public sk_gpu_test::VkTestContext {
 public:
     static VkTestContext* Create(VkTestContext* sharedContext) {
-        GrVkBackendContext backendContext;
-        bool ownsContext = true;
+        sk_sp<const GrVkBackendContext> backendContext;
         if (sharedContext) {
             backendContext = sharedContext->getVkBackendContext();
-            // We always delete the parent context last so make sure the child does not think they
-            // own the vulkan context.
-            ownsContext = false;
         } else {
             PFN_vkGetInstanceProcAddr instProc;
             PFN_vkGetDeviceProcAddr devProc;
             if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
                 return nullptr;
             }
-            if (!sk_gpu_test::CreateVkBackendContext(instProc, devProc, &backendContext)) {
-                return nullptr;
-            }
+            backendContext.reset(GrVkBackendContext::Create(instProc, devProc));
         }
-        return new VkTestContextImpl(backendContext, ownsContext);
+        if (!backendContext) {
+            return nullptr;
+        }
+        return new VkTestContextImpl(std::move(backendContext));
     }
 
     ~VkTestContextImpl() override { this->teardown(); }
@@ -146,19 +143,14 @@
 protected:
     void teardown() override {
         INHERITED::teardown();
-        fVk.fMemoryAllocator.reset();
-        if (fOwnsContext) {
-            GR_VK_CALL(this->vk(), DeviceWaitIdle(fVk.fDevice));
-            GR_VK_CALL(this->vk(), DestroyDevice(fVk.fDevice, nullptr));
-            GR_VK_CALL(this->vk(), DestroyInstance(fVk.fInstance, nullptr));
-        }
+        fVk.reset(nullptr);
     }
 
 private:
-    VkTestContextImpl(const GrVkBackendContext& backendContext, bool ownsContext)
-            : VkTestContext(backendContext, ownsContext) {
-        fFenceSync.reset(new VkFenceSync(fVk.fInterface, fVk.fDevice, fVk.fQueue,
-                                         fVk.fGraphicsQueueIndex));
+    VkTestContextImpl(sk_sp<const GrVkBackendContext> backendContext)
+            : VkTestContext(std::move(backendContext)) {
+        fFenceSync.reset(new VkFenceSync(fVk->fInterface, fVk->fDevice, fVk->fQueue,
+                                         fVk->fGraphicsQueueIndex));
     }
 
     void onPlatformMakeCurrent() const override {}
diff --git a/tools/gpu/vk/VkTestContext.h b/tools/gpu/vk/VkTestContext.h
index 0e62cc0..9fd4170 100644
--- a/tools/gpu/vk/VkTestContext.h
+++ b/tools/gpu/vk/VkTestContext.h
@@ -19,18 +19,16 @@
 public:
     virtual GrBackend backend() override { return kVulkan_GrBackend; }
 
-    const GrVkBackendContext& getVkBackendContext() {
+    sk_sp<const GrVkBackendContext> getVkBackendContext() {
         return fVk;
     }
 
-    const GrVkInterface* vk() const { return fVk.fInterface.get(); }
+    const GrVkInterface* vk() const { return fVk->fInterface.get(); }
 
 protected:
-    VkTestContext(const GrVkBackendContext& vk, bool ownsContext)
-            : fVk(vk), fOwnsContext(ownsContext) {}
+    VkTestContext(sk_sp<const GrVkBackendContext> vk) : fVk(std::move(vk)) {}
 
-    GrVkBackendContext fVk;
-    bool fOwnsContext;
+    sk_sp<const GrVkBackendContext> fVk;
 
 private:
     typedef TestContext INHERITED;
diff --git a/tools/gpu/vk/VkTestUtils.cpp b/tools/gpu/vk/VkTestUtils.cpp
index 927f4fb..c28a42b 100644
--- a/tools/gpu/vk/VkTestUtils.cpp
+++ b/tools/gpu/vk/VkTestUtils.cpp
@@ -9,9 +9,6 @@
 
 #ifdef SK_VULKAN
 
-#include "SkAutoMalloc.h"
-#include "vk/GrVkBackendContext.h"
-#include "vk/GrVkExtensions.h"
 #include "../ports/SkOSLibrary.h"
 
 namespace sk_gpu_test {
@@ -49,323 +46,6 @@
     return true;
 #endif
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// Helper code to set up Vulkan context objects
-
-#ifdef SK_ENABLE_VK_LAYERS
-const char* kDebugLayerNames[] = {
-    // elements of VK_LAYER_LUNARG_standard_validation
-    "VK_LAYER_GOOGLE_threading",
-    "VK_LAYER_LUNARG_parameter_validation",
-    "VK_LAYER_LUNARG_object_tracker",
-    "VK_LAYER_LUNARG_image",
-    "VK_LAYER_LUNARG_core_validation",
-    "VK_LAYER_LUNARG_swapchain",
-    "VK_LAYER_GOOGLE_unique_objects",
-    // not included in standard_validation
-    //"VK_LAYER_LUNARG_api_dump",
-    //"VK_LAYER_LUNARG_vktrace",
-    //"VK_LAYER_LUNARG_screenshot",
-};
-#endif
-
-// the minimum version of Vulkan supported
-#ifdef SK_BUILD_FOR_ANDROID
-const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3);
-#else
-const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 8);
-#endif
-
-#define ACQUIRE_VK_PROC(name, instance, device)                                \
-    PFN_vk##name grVk##name =                                                  \
-        reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
-    if (grVk##name == nullptr) {                                               \
-        SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
-        return false;                                                          \
-    }
-
-bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstanceProc,
-                            const GrVkInterface::GetDeviceProc& getDeviceProc,
-                            GrVkBackendContext* ctx,
-                            uint32_t* presentQueueIndexPtr,
-                            CanPresentFn canPresent) {
-    auto getProc = [&getInstanceProc, &getDeviceProc](const char* proc_name,
-                                                      VkInstance instance, VkDevice device) {
-        if (device != VK_NULL_HANDLE) {
-            return getDeviceProc(device, proc_name);
-        }
-        return getInstanceProc(instance, proc_name);
-    };
-
-    VkPhysicalDevice physDev;
-    VkDevice device;
-    VkInstance inst;
-    VkResult err;
-
-    const VkApplicationInfo app_info = {
-        VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
-        nullptr,                            // pNext
-        "vktest",                           // pApplicationName
-        0,                                  // applicationVersion
-        "vktest",                           // pEngineName
-        0,                                  // engineVerison
-        kGrVkMinimumVersion,                // apiVersion
-    };
-
-    GrVkExtensions extensions(getProc);
-    extensions.initInstance(kGrVkMinimumVersion);
-
-    SkTArray<const char*> instanceLayerNames;
-    SkTArray<const char*> instanceExtensionNames;
-    uint32_t extensionFlags = 0;
-#ifdef SK_ENABLE_VK_LAYERS
-    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
-        if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
-            instanceLayerNames.push_back(kDebugLayerNames[i]);
-        }
-    }
-    if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
-        extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
-    }
-#endif
-
-    if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
-        extensionFlags |= kKHR_surface_GrVkExtensionFlag;
-    }
-    if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
-        extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
-    }
-#ifdef SK_BUILD_FOR_WIN
-    if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
-        extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
-    }
-#elif defined(SK_BUILD_FOR_ANDROID)
-    if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
-        extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
-    }
-#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
-    if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
-        extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
-    }
-#endif
-
-    const VkInstanceCreateInfo instance_create = {
-        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
-        nullptr,                                   // pNext
-        0,                                         // flags
-        &app_info,                                 // pApplicationInfo
-        (uint32_t) instanceLayerNames.count(),     // enabledLayerNameCount
-        instanceLayerNames.begin(),                // ppEnabledLayerNames
-        (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
-        instanceExtensionNames.begin(),            // ppEnabledExtensionNames
-    };
-
-    ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
-    err = grVkCreateInstance(&instance_create, nullptr, &inst);
-    if (err < 0) {
-        SkDebugf("vkCreateInstance failed: %d\n", err);
-        return false;
-    }
-
-    ACQUIRE_VK_PROC(DestroyInstance, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
-    ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
-
-    uint32_t gpuCount;
-    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
-    if (err) {
-        SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-    if (!gpuCount) {
-        SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-    // Just returning the first physical device instead of getting the whole array.
-    // TODO: find best match for our needs
-    gpuCount = 1;
-    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
-    // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
-    if (err && VK_INCOMPLETE != err) {
-        SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-
-    // query to get the initial queue props size
-    uint32_t queueCount;
-    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
-    if (!queueCount) {
-        SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-
-    SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
-    // now get the actual queue props
-    VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
-
-    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
-
-    // iterate to find the graphics queue
-    uint32_t graphicsQueueIndex = queueCount;
-    for (uint32_t i = 0; i < queueCount; i++) {
-        if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
-            graphicsQueueIndex = i;
-            break;
-        }
-    }
-    if (graphicsQueueIndex == queueCount) {
-        SkDebugf("Could not find any supported graphics queues.\n");
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-
-    // iterate to find the present queue, if needed
-    uint32_t presentQueueIndex = queueCount;
-    if (presentQueueIndexPtr && canPresent) {
-        for (uint32_t i = 0; i < queueCount; i++) {
-            if (canPresent(inst, physDev, i)) {
-                presentQueueIndex = i;
-                break;
-            }
-        }
-        if (presentQueueIndex == queueCount) {
-            SkDebugf("Could not find any supported present queues.\n");
-            grVkDestroyInstance(inst, nullptr);
-            return false;
-        }
-        *presentQueueIndexPtr = presentQueueIndex;
-    } else {
-        // Just setting this so we end up make a single queue for graphics since there was no
-        // request for a present queue.
-        presentQueueIndex = graphicsQueueIndex;
-    }
-
-    extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
-
-    SkTArray<const char*> deviceLayerNames;
-    SkTArray<const char*> deviceExtensionNames;
-#ifdef SK_ENABLE_VK_LAYERS
-    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
-        if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
-            deviceLayerNames.push_back(kDebugLayerNames[i]);
-        }
-    }
-#endif
-    if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
-        deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
-        extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
-    }
-    if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
-        deviceExtensionNames.push_back("VK_NV_glsl_shader");
-        extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
-    }
-
-    // query to get the physical device properties
-    VkPhysicalDeviceFeatures deviceFeatures;
-    grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
-    // this looks like it would slow things down,
-    // and we can't depend on it on all platforms
-    deviceFeatures.robustBufferAccess = VK_FALSE;
-
-    uint32_t featureFlags = 0;
-    if (deviceFeatures.geometryShader) {
-        featureFlags |= kGeometryShader_GrVkFeatureFlag;
-    }
-    if (deviceFeatures.dualSrcBlend) {
-        featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
-    }
-    if (deviceFeatures.sampleRateShading) {
-        featureFlags |= kSampleRateShading_GrVkFeatureFlag;
-    }
-
-    float queuePriorities[1] = { 0.0 };
-    // Here we assume no need for swapchain queue
-    // If one is needed, the client will need its own setup code
-    const VkDeviceQueueCreateInfo queueInfo[2] = {
-        {
-            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
-            nullptr,                                    // pNext
-            0,                                          // VkDeviceQueueCreateFlags
-            graphicsQueueIndex,                         // queueFamilyIndex
-            1,                                          // queueCount
-            queuePriorities,                            // pQueuePriorities
-        },
-        {
-            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
-            nullptr,                                    // pNext
-            0,                                          // VkDeviceQueueCreateFlags
-            presentQueueIndex,                          // queueFamilyIndex
-            1,                                          // queueCount
-            queuePriorities,                            // pQueuePriorities
-        }
-    };
-    uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
-
-    const VkDeviceCreateInfo deviceInfo = {
-        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,    // sType
-        nullptr,                                 // pNext
-        0,                                       // VkDeviceCreateFlags
-        queueInfoCount,                          // queueCreateInfoCount
-        queueInfo,                               // pQueueCreateInfos
-        (uint32_t) deviceLayerNames.count(),     // layerCount
-        deviceLayerNames.begin(),                // ppEnabledLayerNames
-        (uint32_t) deviceExtensionNames.count(), // extensionCount
-        deviceExtensionNames.begin(),            // ppEnabledExtensionNames
-        &deviceFeatures                          // ppEnabledFeatures
-    };
-
-    err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
-    if (err) {
-        SkDebugf("CreateDevice failed: %d\n", err);
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-
-    auto interface =
-        sk_make_sp<GrVkInterface>(getProc, inst, device, extensionFlags);
-    if (!interface->validate(extensionFlags)) {
-        SkDebugf("Vulkan interface validation failed\n");
-        grVkDeviceWaitIdle(device);
-        grVkDestroyDevice(device, nullptr);
-        grVkDestroyInstance(inst, nullptr);
-        return false;
-    }
-
-    VkQueue queue;
-    grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
-
-    ctx->fInstance = inst;
-    ctx->fPhysicalDevice = physDev;
-    ctx->fDevice = device;
-    ctx->fQueue = queue;
-    ctx->fGraphicsQueueIndex = graphicsQueueIndex;
-    ctx->fMinAPIVersion = kGrVkMinimumVersion;
-    ctx->fExtensions = extensionFlags;
-    ctx->fFeatures = featureFlags;
-    ctx->fInterface.reset(interface.release());
-    ctx->fOwnsInstanceAndDevice = false;
-
-    return true;
-
-
-}
-
 }
 
 #endif
diff --git a/tools/gpu/vk/VkTestUtils.h b/tools/gpu/vk/VkTestUtils.h
index 30471a78..9f34ef0 100644
--- a/tools/gpu/vk/VkTestUtils.h
+++ b/tools/gpu/vk/VkTestUtils.h
@@ -13,21 +13,9 @@
 #ifdef SK_VULKAN
 
 #include "vk/GrVkDefines.h"
-#include "vk/GrVkInterface.h"
-
-struct GrVkBackendContext;
 
 namespace sk_gpu_test {
     bool LoadVkLibraryAndGetProcAddrFuncs(PFN_vkGetInstanceProcAddr*, PFN_vkGetDeviceProcAddr*);
-
-    using CanPresentFn = std::function<bool(VkInstance, VkPhysicalDevice,
-                                            uint32_t queueFamilyIndex)>;
-
-    bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstanceProc,
-                                const GrVkInterface::GetDeviceProc& getDeviceProc,
-                                GrVkBackendContext* ctx,
-                                uint32_t* presentQueueIndexPtr = nullptr,
-                                CanPresentFn canPresent = CanPresentFn());
 }
 
 #endif
diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp
index 411f114..ad0e15c 100644
--- a/tools/sk_app/VulkanWindowContext.cpp
+++ b/tools/sk_app/VulkanWindowContext.cpp
@@ -13,6 +13,7 @@
 #include "VulkanWindowContext.h"
 
 #include "vk/GrVkImage.h"
+#include "vk/GrVkInterface.h"
 #include "vk/GrVkUtil.h"
 #include "vk/GrVkTypes.h"
 
@@ -21,8 +22,8 @@
 #undef CreateSemaphore
 #endif
 
-#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
-#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F)
+#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(instance, "vk" #F)
+#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(device, "vk" #F)
 
 namespace sk_app {
 
@@ -48,34 +49,22 @@
 
 void VulkanWindowContext::initializeContext() {
     // any config code here (particularly for msaa)?
+    fBackendContext.reset(GrVkBackendContext::Create(fGetInstanceProcAddr, fGetDeviceProcAddr,
+                                                     &fPresentQueueIndex, fCanPresentFn));
 
-    GrVkBackendContext backendContext;
-    if (!sk_gpu_test::CreateVkBackendContext(fGetInstanceProcAddr, fGetDeviceProcAddr,
-                                             &backendContext, &fPresentQueueIndex, fCanPresentFn)) {
+    if (!(fBackendContext->fExtensions & kKHR_surface_GrVkExtensionFlag) ||
+        !(fBackendContext->fExtensions & kKHR_swapchain_GrVkExtensionFlag)) {
+        fBackendContext.reset(nullptr);
         return;
     }
 
-    if (!(backendContext.fExtensions & kKHR_surface_GrVkExtensionFlag) ||
-        !(backendContext.fExtensions & kKHR_swapchain_GrVkExtensionFlag)) {
-        return;
-    }
-
-    fInstance = backendContext.fInstance;
-    fPhysicalDevice = backendContext.fPhysicalDevice;
-    fDevice = backendContext.fDevice;
-    fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
-    fGraphicsQueue = backendContext.fQueue;
-    fInterface = backendContext.fInterface;
-
-    GET_PROC(DestroyInstance);
+    VkInstance instance = fBackendContext->fInstance;
+    VkDevice device = fBackendContext->fDevice;
     GET_PROC(DestroySurfaceKHR);
     GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
     GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
     GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
     GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
-    GET_DEV_PROC(DeviceWaitIdle);
-    GET_DEV_PROC(QueueWaitIdle);
-    GET_DEV_PROC(DestroyDevice);
     GET_DEV_PROC(CreateSwapchainKHR);
     GET_DEV_PROC(DestroySwapchainKHR);
     GET_DEV_PROC(GetSwapchainImagesKHR);
@@ -83,17 +72,18 @@
     GET_DEV_PROC(QueuePresentKHR);
     GET_DEV_PROC(GetDeviceQueue);
 
-    fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
+    fContext = GrContext::MakeVulkan(fBackendContext, fDisplayParams.fGrContextOptions);
 
-    fSurface = fCreateVkSurfaceFn(fInstance);
+    fSurface = fCreateVkSurfaceFn(instance);
     if (VK_NULL_HANDLE == fSurface) {
-        this->destroyContext();
+        fBackendContext.reset(nullptr);
         return;
     }
 
     VkBool32 supported;
-    VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
-                                                       fSurface, &supported);
+    VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fBackendContext->fPhysicalDevice,
+                                                       fPresentQueueIndex, fSurface,
+                                                       &supported);
     if (VK_SUCCESS != res) {
         this->destroyContext();
         return;
@@ -105,44 +95,45 @@
     }
 
     // create presentQueue
-    fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
+    fGetDeviceQueue(fBackendContext->fDevice, fPresentQueueIndex, 0, &fPresentQueue);
 }
 
 bool VulkanWindowContext::createSwapchain(int width, int height,
                                           const DisplayParams& params) {
     // check for capabilities
     VkSurfaceCapabilitiesKHR caps;
-    VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
+    VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice,
+                                                            fSurface, &caps);
     if (VK_SUCCESS != res) {
         return false;
     }
 
     uint32_t surfaceFormatCount;
-    res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
-                                              nullptr);
+    res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
+                                              &surfaceFormatCount, nullptr);
     if (VK_SUCCESS != res) {
         return false;
     }
 
     SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
     VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
-    res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
-                                              surfaceFormats);
+    res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
+                                              &surfaceFormatCount, surfaceFormats);
     if (VK_SUCCESS != res) {
         return false;
     }
 
     uint32_t presentModeCount;
-    res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
-                                                   nullptr);
+    res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
+                                                   &presentModeCount, nullptr);
     if (VK_SUCCESS != res) {
         return false;
     }
 
     SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
     VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
-    res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
-                                                   presentModes);
+    res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
+                                                   &presentModeCount, presentModes);
     if (VK_SUCCESS != res) {
         return false;
     }
@@ -243,8 +234,8 @@
     swapchainCreateInfo.imageArrayLayers = 1;
     swapchainCreateInfo.imageUsage = usageFlags;
 
-    uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
-    if (fGraphicsQueueIndex != fPresentQueueIndex) {
+    uint32_t queueFamilies[] = { fBackendContext->fGraphicsQueueIndex, fPresentQueueIndex };
+    if (fBackendContext->fGraphicsQueueIndex != fPresentQueueIndex) {
         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
         swapchainCreateInfo.queueFamilyIndexCount = 2;
         swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
@@ -260,18 +251,18 @@
     swapchainCreateInfo.clipped = true;
     swapchainCreateInfo.oldSwapchain = fSwapchain;
 
-    res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
+    res = fCreateSwapchainKHR(fBackendContext->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
     if (VK_SUCCESS != res) {
         return false;
     }
 
     // destroy the old swapchain
     if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
-        fDeviceWaitIdle(fDevice);
+        GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
 
         this->destroyBuffers();
 
-        fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
+        fDestroySwapchainKHR(fBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
     }
 
     this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
@@ -280,10 +271,10 @@
 }
 
 void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
-    fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
+    fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, nullptr);
     SkASSERT(fImageCount);
     fImages = new VkImage[fImageCount];
-    fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
+    fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, fImages);
 
     // set up initial image layouts and create surfaces
     fImageLayouts = new VkImageLayout[fImageCount];
@@ -315,10 +306,10 @@
         memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
         commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
         // this needs to be on the render queue
-        commandPoolInfo.queueFamilyIndex = fGraphicsQueueIndex;
+        commandPoolInfo.queueFamilyIndex = fBackendContext->fGraphicsQueueIndex;
         commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            CreateCommandPool(fDevice, &commandPoolInfo,
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo,
                                               nullptr, &fCommandPool));
     }
 
@@ -346,20 +337,20 @@
     fBackbuffers = new BackbufferInfo[fImageCount + 1];
     for (uint32_t i = 0; i < fImageCount + 1; ++i) {
         fBackbuffers[i].fImageIndex = -1;
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            CreateSemaphore(fDevice, &semaphoreInfo,
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
                                             nullptr, &fBackbuffers[i].fAcquireSemaphore));
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            CreateSemaphore(fDevice, &semaphoreInfo,
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
                                             nullptr, &fBackbuffers[i].fRenderSemaphore));
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            AllocateCommandBuffers(fDevice, &commandBuffersInfo,
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo,
                                                    fBackbuffers[i].fTransitionCmdBuffers));
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            CreateFence(fDevice, &fenceInfo, nullptr,
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
                                         &fBackbuffers[i].fUsageFences[0]));
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            CreateFence(fDevice, &fenceInfo, nullptr,
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
                                         &fBackbuffers[i].fUsageFences[1]));
     }
     fCurrentBackbufferIndex = fImageCount;
@@ -369,26 +360,26 @@
 
     if (fBackbuffers) {
         for (uint32_t i = 0; i < fImageCount + 1; ++i) {
-            GR_VK_CALL_ERRCHECK(fInterface,
-                                WaitForFences(fDevice, 2,
+            GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                                WaitForFences(fBackendContext->fDevice, 2,
                                               fBackbuffers[i].fUsageFences,
                                               true, UINT64_MAX));
             fBackbuffers[i].fImageIndex = -1;
-            GR_VK_CALL(fInterface,
-                       DestroySemaphore(fDevice,
+            GR_VK_CALL(fBackendContext->fInterface,
+                       DestroySemaphore(fBackendContext->fDevice,
                                         fBackbuffers[i].fAcquireSemaphore,
                                         nullptr));
-            GR_VK_CALL(fInterface,
-                       DestroySemaphore(fDevice,
+            GR_VK_CALL(fBackendContext->fInterface,
+                       DestroySemaphore(fBackendContext->fDevice,
                                         fBackbuffers[i].fRenderSemaphore,
                                         nullptr));
-            GR_VK_CALL(fInterface,
-                       FreeCommandBuffers(fDevice, fCommandPool, 2,
+            GR_VK_CALL(fBackendContext->fInterface,
+                       FreeCommandBuffers(fBackendContext->fDevice, fCommandPool, 2,
                                           fBackbuffers[i].fTransitionCmdBuffers));
-            GR_VK_CALL(fInterface,
-                       DestroyFence(fDevice, fBackbuffers[i].fUsageFences[0], 0));
-            GR_VK_CALL(fInterface,
-                       DestroyFence(fDevice, fBackbuffers[i].fUsageFences[1], 0));
+            GR_VK_CALL(fBackendContext->fInterface,
+                       DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[0], 0));
+            GR_VK_CALL(fBackendContext->fInterface,
+                       DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[1], 0));
         }
     }
 
@@ -409,43 +400,34 @@
 }
 
 void VulkanWindowContext::destroyContext() {
-    if (!this->isValid()) {
+    if (!fBackendContext.get()) {
         return;
     }
 
-    fQueueWaitIdle(fPresentQueue);
-    fDeviceWaitIdle(fDevice);
+    GR_VK_CALL(fBackendContext->fInterface, QueueWaitIdle(fPresentQueue));
+    GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
 
     this->destroyBuffers();
 
     if (VK_NULL_HANDLE != fCommandPool) {
-        GR_VK_CALL(fInterface, DestroyCommandPool(fDevice, fCommandPool, nullptr));
+        GR_VK_CALL(fBackendContext->fInterface, DestroyCommandPool(fBackendContext->fDevice,
+                                                                   fCommandPool, nullptr));
         fCommandPool = VK_NULL_HANDLE;
     }
 
     if (VK_NULL_HANDLE != fSwapchain) {
-        fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
+        fDestroySwapchainKHR(fBackendContext->fDevice, fSwapchain, nullptr);
         fSwapchain = VK_NULL_HANDLE;
     }
 
     if (VK_NULL_HANDLE != fSurface) {
-        fDestroySurfaceKHR(fInstance, fSurface, nullptr);
+        fDestroySurfaceKHR(fBackendContext->fInstance, fSurface, nullptr);
         fSurface = VK_NULL_HANDLE;
     }
 
     fContext.reset();
-    fInterface.reset();
 
-    if (VK_NULL_HANDLE != fDevice) {
-        fDestroyDevice(fDevice, nullptr);
-        fDevice = VK_NULL_HANDLE;
-    }
-    fPhysicalDevice = VK_NULL_HANDLE;
-
-    if (VK_NULL_HANDLE != fInstance) {
-        fDestroyInstance(fInstance, nullptr);
-        fInstance = VK_NULL_HANDLE;
-    }
+    fBackendContext.reset(nullptr);
 }
 
 VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
@@ -457,8 +439,8 @@
     }
 
     BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
-    GR_VK_CALL_ERRCHECK(fInterface,
-                        WaitForFences(fDevice, 2, backbuffer->fUsageFences,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                        WaitForFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences,
                                       true, UINT64_MAX));
     return backbuffer;
 }
@@ -468,12 +450,12 @@
     SkASSERT(backbuffer);
 
     // reset the fence
-    GR_VK_CALL_ERRCHECK(fInterface,
-                        ResetFences(fDevice, 2, backbuffer->fUsageFences));
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                        ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
     // semaphores should be in unsignaled state
 
     // acquire the image
-    VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
+    VkResult res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
                                         backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
                                         &backbuffer->fImageIndex);
     if (VK_ERROR_SURFACE_LOST_KHR == res) {
@@ -487,11 +469,11 @@
             return nullptr;
         }
         backbuffer = this->getAvailableBackbuffer();
-        GR_VK_CALL_ERRCHECK(fInterface,
-                            ResetFences(fDevice, 2, backbuffer->fUsageFences));
+        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                            ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
 
         // acquire the image
-        res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
+        res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
                                    backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
                                    &backbuffer->fImageIndex);
 
@@ -519,27 +501,27 @@
         layout,                                   // oldLayout
         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
         fPresentQueueIndex,                       // srcQueueFamilyIndex
-        fGraphicsQueueIndex,                      // dstQueueFamilyIndex
+        fBackendContext->fGraphicsQueueIndex,     // dstQueueFamilyIndex
         fImages[backbuffer->fImageIndex],         // image
         { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
     };
-    GR_VK_CALL_ERRCHECK(fInterface,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                         ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
     VkCommandBufferBeginInfo info;
     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
     info.flags = 0;
-    GR_VK_CALL_ERRCHECK(fInterface,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                         BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
 
-    GR_VK_CALL(fInterface,
+    GR_VK_CALL(fBackendContext->fInterface,
                CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
                                   srcStageMask, dstStageMask, 0,
                                   0, nullptr,
                                   0, nullptr,
                                   1, &imageMemoryBarrier));
 
-    GR_VK_CALL_ERRCHECK(fInterface,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                         EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
 
     VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
@@ -554,8 +536,8 @@
     submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
     submitInfo.signalSemaphoreCount = 0;
 
-    GR_VK_CALL_ERRCHECK(fInterface,
-                        QueueSubmit(fGraphicsQueue, 1, &submitInfo,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                        QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
                                     backbuffer->fUsageFences[0]));
 
     SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
@@ -592,26 +574,26 @@
         dstAccessMask,                            // inputMask
         layout,                                   // oldLayout
         VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,          // newLayout
-        fGraphicsQueueIndex,                      // srcQueueFamilyIndex
+        fBackendContext->fGraphicsQueueIndex,     // srcQueueFamilyIndex
         fPresentQueueIndex,                       // dstQueueFamilyIndex
         fImages[backbuffer->fImageIndex],         // image
         { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
     };
-    GR_VK_CALL_ERRCHECK(fInterface,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                         ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
     VkCommandBufferBeginInfo info;
     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
     info.flags = 0;
-    GR_VK_CALL_ERRCHECK(fInterface,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                         BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
-    GR_VK_CALL(fInterface,
+    GR_VK_CALL(fBackendContext->fInterface,
                CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
                                   srcStageMask, dstStageMask, 0,
                                   0, nullptr,
                                   0, nullptr,
                                   1, &imageMemoryBarrier));
-    GR_VK_CALL_ERRCHECK(fInterface,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
                         EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
 
     fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
@@ -627,8 +609,8 @@
     submitInfo.signalSemaphoreCount = 1;
     submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
 
-    GR_VK_CALL_ERRCHECK(fInterface,
-                        QueueSubmit(fGraphicsQueue, 1, &submitInfo,
+    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
+                        QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
                                     backbuffer->fUsageFences[1]));
 
     // Submit present operation to present queue
diff --git a/tools/sk_app/VulkanWindowContext.h b/tools/sk_app/VulkanWindowContext.h
index 79298f6..1fca9dc 100644
--- a/tools/sk_app/VulkanWindowContext.h
+++ b/tools/sk_app/VulkanWindowContext.h
@@ -13,8 +13,6 @@
 #ifdef SK_VULKAN
 
 #include "vk/GrVkBackendContext.h"
-#include "vk/GrVkInterface.h"
-#include "vk/VkTestUtils.h"
 #include "WindowContext.h"
 
 class GrRenderTarget;
@@ -28,7 +26,7 @@
     sk_sp<SkSurface> getBackbufferSurface() override;
     void swapBuffers() override;
 
-    bool isValid() override { return fDevice != VK_NULL_HANDLE; }
+    bool isValid() override { return SkToBool(fBackendContext.get()); }
 
     void resize(int w, int h) override {
         this->createSwapchain(w, h, fDisplayParams);
@@ -43,7 +41,7 @@
     /** Platform specific function that creates a VkSurfaceKHR for a window */
     using CreateVkSurfaceFn = std::function<VkSurfaceKHR(VkInstance)>;
     /** Platform specific function that determines whether presentation will succeed. */
-    using CanPresentFn = sk_gpu_test::CanPresentFn;
+    using CanPresentFn = GrVkBackendContext::CanPresentFn;
 
     VulkanWindowContext(const DisplayParams&, CreateVkSurfaceFn, CanPresentFn,
                         PFN_vkGetInstanceProcAddr, PFN_vkGetDeviceProcAddr);
@@ -65,9 +63,7 @@
     void createBuffers(VkFormat format, SkColorType colorType);
     void destroyBuffers();
 
-    VkInstance fInstance = VK_NULL_HANDLE;
-    VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE;
-    VkDevice fDevice = VK_NULL_HANDLE;
+    sk_sp<const GrVkBackendContext> fBackendContext;
 
     // simple wrapper class that exists only to initialize a pointer to NULL
     template <typename FNPTR_TYPE> class VkPtr {
@@ -99,19 +95,10 @@
     VkPtr<PFN_vkGetSwapchainImagesKHR> fGetSwapchainImagesKHR;
     VkPtr<PFN_vkAcquireNextImageKHR> fAcquireNextImageKHR;
     VkPtr<PFN_vkQueuePresentKHR> fQueuePresentKHR;
-
-    VkPtr<PFN_vkDestroyInstance> fDestroyInstance;
-    VkPtr<PFN_vkDeviceWaitIdle> fDeviceWaitIdle;
-    VkPtr<PFN_vkQueueWaitIdle> fQueueWaitIdle;
-    VkPtr<PFN_vkDestroyDevice> fDestroyDevice;
     VkPtr<PFN_vkGetDeviceQueue> fGetDeviceQueue;
 
-    sk_sp<const GrVkInterface> fInterface;
-
     VkSurfaceKHR      fSurface;
     VkSwapchainKHR    fSwapchain;
-    uint32_t          fGraphicsQueueIndex;
-    VkQueue           fGraphicsQueue;
     uint32_t          fPresentQueueIndex;
     VkQueue           fPresentQueue;