Let client pass in full extension to GrVkBackendContext.

Bug: skia:
Change-Id: I772ab4ccbca0f4f7e7d429d6c421b07d97f0606f
Reviewed-on: https://skia-review.googlesource.com/131880
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index aac5640..d150dd5 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -537,6 +537,7 @@
 skia_vk_sources = [
   "$_include/gpu/vk/GrVkBackendContext.h",
   "$_include/gpu/vk/GrVkDefines.h",
+  "$_include/gpu/vk/GrVkExtensions.h",
   "$_include/gpu/vk/GrVkInterface.h",
   "$_include/gpu/vk/GrVkMemoryAllocator.h",
   "$_include/gpu/vk/GrVkTypes.h",
@@ -562,7 +563,6 @@
   "$_src/gpu/vk/GrVkDescriptorSetManager.cpp",
   "$_src/gpu/vk/GrVkDescriptorSetManager.h",
   "$_src/gpu/vk/GrVkExtensions.cpp",
-  "$_src/gpu/vk/GrVkExtensions.h",
   "$_src/gpu/vk/GrVkFramebuffer.cpp",
   "$_src/gpu/vk/GrVkFramebuffer.h",
   "$_src/gpu/vk/GrVkGpu.cpp",
diff --git a/include/gpu/vk/GrVkBackendContext.h b/include/gpu/vk/GrVkBackendContext.h
index fe018e4..3775c34 100644
--- a/include/gpu/vk/GrVkBackendContext.h
+++ b/include/gpu/vk/GrVkBackendContext.h
@@ -49,7 +49,6 @@
     uint32_t                   fFeatures;
     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;
diff --git a/include/gpu/vk/GrVkExtensions.h b/include/gpu/vk/GrVkExtensions.h
new file mode 100644
index 0000000..a6badcd
--- /dev/null
+++ b/include/gpu/vk/GrVkExtensions.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVkExtensions_DEFINED
+#define GrVkExtensions_DEFINED
+
+#include "../private/SkTArray.h"
+#include "SkString.h"
+
+/**
+ * Helper class that eats in an array of extensions strings for instance and device and allows for
+ * quicker querying if an extension is present.
+ */
+class GrVkExtensions {
+public:
+    GrVkExtensions(uint32_t instanceExtensionCount, const char* const* instanceExtensions,
+                   uint32_t deviceExtensionCount, const char* const* deviceExtensions);
+    // TODO: Remove once we remove the old fExtensions from GrVkBackendContext
+    GrVkExtensions(uint32_t extensionFlags);
+
+    // TODO: Remove once we remove the old fExtensions from GrVkBackendContext
+    static void GetExtensionArrayFromFlags(uint32_t extensionFlags,
+                                           SkTArray<const char*>* extensions);
+
+    bool hasExtension(const char[]) const;
+
+private:
+    SkTArray<SkString>  fExtensionStrings;
+};
+
+#endif
diff --git a/include/gpu/vk/GrVkInterface.h b/include/gpu/vk/GrVkInterface.h
index 05ce561..b4691e8 100644
--- a/include/gpu/vk/GrVkInterface.h
+++ b/include/gpu/vk/GrVkInterface.h
@@ -11,6 +11,7 @@
 #include "SkRefCnt.h"
 
 #include "vk/GrVkDefines.h"
+#include "vk/GrVkExtensions.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -50,17 +51,25 @@
     GrVkInterface(GetProc getProc,
                   VkInstance instance,
                   VkDevice device,
-                  uint32_t extensionFlags);
+                  uint32_t instanceExtensionCount,
+                  const char* const* instanceExtensions,
+                  uint32_t deviceExtensionCount,
+                  const char* const* deviceExtensions);
 
-    GrVkInterface(const GetInstanceProc&,
-                  const GetDeviceProc&,
+    // TODO: This is deprecated. Remove onces clients have switch to new interface
+    GrVkInterface(GetProc getProc,
                   VkInstance instance,
                   VkDevice device,
                   uint32_t extensionFlags);
 
     // Validates that the GrVkInterface supports its advertised standard. This means the necessary
     // function pointers have been initialized for Vulkan version.
-    bool validate(uint32_t extensionFlags) const;
+    bool validate() const;
+
+    // This is deprecated since the extensions information is stored already on the GrVkInterface.
+    bool validate(uint32_t /*extensionFlags*/) const {
+        return this->validate();
+    }
 
     /**
      * The function pointers are in a struct so that we can have a compiler generated assignment
@@ -208,6 +217,10 @@
         VkPtr<PFN_vkDestroyDebugReportCallbackEXT> fDestroyDebugReportCallbackEXT;
     } fFunctions;
 
+    GrVkExtensions fExtensions;
+
+private:
+    void init(GetProc getProc, VkInstance instance, VkDevice device);
 };
 
 #endif
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 1a14648..d1dfcf0 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -15,9 +15,8 @@
 #include "vk/GrVkInterface.h"
 
 GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
-                   VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags)
+                   VkPhysicalDevice physDev, uint32_t featureFlags)
     : INHERITED(contextOptions) {
-    fCanUseGLSLForShaderModule = false;
     fMustDoCopiesFromOrigin = false;
     fMustSubmitCommandsBeforeCopyOp = false;
     fMustSleepOnTearDown  = false;
@@ -48,7 +47,7 @@
 
     fShaderCaps.reset(new GrShaderCaps(contextOptions));
 
-    this->init(contextOptions, vkInterface, physDev, featureFlags, extensionFlags);
+    this->init(contextOptions, vkInterface, physDev, featureFlags);
 }
 
 bool GrVkCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
@@ -196,7 +195,7 @@
 }
 
 void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
-                    VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags) {
+                    VkPhysicalDevice physDev, uint32_t featureFlags) {
 
     VkPhysicalDeviceProperties properties;
     GR_VK_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &properties));
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 2ed2254..6e23af0 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -27,7 +27,7 @@
      * be called to fill out the caps.
      */
     GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
-             VkPhysicalDevice device, uint32_t featureFlags, uint32_t extensionFlags);
+             VkPhysicalDevice device, uint32_t featureFlags);
 
     bool isConfigTexturable(GrPixelConfig config) const override {
         return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fOptimalFlags);
@@ -64,11 +64,6 @@
         return SkToBool(ConfigInfo::kBlitSrc_Flag & flags);
     }
 
-    // Tells of if we can pass in straight GLSL string into vkCreateShaderModule
-    bool canUseGLSLForShaderModule() const {
-        return fCanUseGLSLForShaderModule;
-    }
-
     // On Adreno vulkan, they do not respect the imageOffset parameter at least in
     // copyImageToBuffer. This flag says that we must do the copy starting from the origin always.
     bool mustDoCopiesFromOrigin() const {
@@ -151,7 +146,7 @@
     };
 
     void init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
-              VkPhysicalDevice device, uint32_t featureFlags, uint32_t extensionFlags);
+              VkPhysicalDevice device, uint32_t featureFlags);
     void initGrCaps(const VkPhysicalDeviceProperties&,
                     const VkPhysicalDeviceMemoryProperties&,
                     uint32_t featureFlags);
@@ -187,7 +182,6 @@
 
     StencilFormat fPreferedStencilFormat;
 
-    bool fCanUseGLSLForShaderModule;
     bool fMustDoCopiesFromOrigin;
     bool fMustSubmitCommandsBeforeCopyOp;
     bool fMustSleepOnTearDown;
diff --git a/src/gpu/vk/GrVkExtensions.cpp b/src/gpu/vk/GrVkExtensions.cpp
index e4768d9..46bb94d 100644
--- a/src/gpu/vk/GrVkExtensions.cpp
+++ b/src/gpu/vk/GrVkExtensions.cpp
@@ -6,7 +6,9 @@
  */
 
 #include "vk/GrVkExtensions.h"
-#include "vk/GrVkUtil.h"
+
+// Can remove this once we get rid of the extension flags.
+#include "vk/GrVkBackendContext.h"
 
 #include "SkTSearch.h"
 #include "SkTSort.h"
@@ -30,232 +32,82 @@
     return idx;
 }
 
-#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) fGetProc("vk" #F, inst, device)
-
-static uint32_t remove_patch_version(uint32_t specVersion) {
-    return (specVersion >> 12) << 12;
-}
-
-bool GrVkExtensions::initInstance(uint32_t specVersion) {
-    if (fGetProc == nullptr) {
-        return false;
-    }
-
-    uint32_t nonPatchVersion = remove_patch_version(specVersion);
-
-    GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
-    GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
-
+GrVkExtensions::GrVkExtensions(uint32_t instanceExtensionCount,
+                               const char* const* instanceExtensions,
+                               uint32_t deviceExtensionCount,
+                               const char* const* deviceExtensions)
+        : fExtensionStrings() {
     SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
 
-    if (!EnumerateInstanceExtensionProperties ||
-        !EnumerateInstanceLayerProperties) {
-        return false;
-    }
-
-    // instance layers
-    uint32_t layerCount = 0;
-    VkResult res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-    VkLayerProperties* layers = new VkLayerProperties[layerCount];
-    res = EnumerateInstanceLayerProperties(&layerCount, layers);
-    if (VK_SUCCESS != res) {
-        delete[] layers;
-        return false;
-    }
-    for (uint32_t i = 0; i < layerCount; ++i) {
-        if (nonPatchVersion <= remove_patch_version(layers[i].specVersion)) {
-            fInstanceLayerStrings->push_back() = layers[i].layerName;
+    for (uint32_t i = 0; i < instanceExtensionCount; ++i) {
+        const char* extension = instanceExtensions[i];
+        // if not already in the list, add it
+        if (find_string(fExtensionStrings, extension) < 0) {
+            fExtensionStrings.push_back() = extension;
+            SkTQSort(&fExtensionStrings.front(), &fExtensionStrings.back(), cmp);
         }
     }
-    delete[] layers;
-    if (!fInstanceLayerStrings->empty()) {
-        SkTQSort(&fInstanceLayerStrings->front(), &fInstanceLayerStrings->back(), cmp);
-    }
-
-    // instance extensions
-    // via Vulkan implementation and implicitly enabled layers
-    uint32_t extensionCount = 0;
-    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
-    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
-    if (VK_SUCCESS != res) {
-        delete[] extensions;
-        return false;
-    }
-    for (uint32_t i = 0; i < extensionCount; ++i) {
-        fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
-    }
-    delete [] extensions;
-    // sort so we can search
-    if (!fInstanceExtensionStrings->empty()) {
-        SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(), cmp);
-    }
-    // via explicitly enabled layers
-    layerCount = fInstanceLayerStrings->count();
-    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
-        uint32_t extensionCount = 0;
-        res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
-                                                   &extensionCount, nullptr);
-        if (VK_SUCCESS != res) {
-            return false;
+    for (uint32_t i = 0; i < deviceExtensionCount; ++i) {
+        const char* extension = deviceExtensions[i];
+        // if not already in the list, add it
+        if (find_string(fExtensionStrings, extension) < 0) {
+            fExtensionStrings.push_back() = extension;
+            SkTQSort(&fExtensionStrings.front(), &fExtensionStrings.back(), cmp);
         }
-        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
-        res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
-                                                   &extensionCount, extensions);
-        if (VK_SUCCESS != res) {
-            delete[] extensions;
-            return false;
-        }
-        for (uint32_t i = 0; i < extensionCount; ++i) {
-            // if not already in the list, add it
-            if (find_string(*fInstanceExtensionStrings, extensions[i].extensionName) < 0) {
-                fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
-                SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(),
-                         cmp);
-            }
-        }
-        delete[] extensions;
     }
-
-    return true;
 }
 
-bool GrVkExtensions::initDevice(uint32_t specVersion, VkInstance inst, VkPhysicalDevice physDev) {
-    if (fGetProc == nullptr) {
-        return false;
-    }
-
-    uint32_t nonPatchVersion = remove_patch_version(specVersion);
-
-    GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
-    GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
-
+GrVkExtensions::GrVkExtensions(uint32_t extensionFlags)
+        : fExtensionStrings() {
     SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
 
-    if (!EnumerateDeviceExtensionProperties ||
-        !EnumerateDeviceLayerProperties) {
-        return false;
-    }
-
-    // device layers
-    uint32_t layerCount = 0;
-    VkResult res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-    VkLayerProperties* layers = new VkLayerProperties[layerCount];
-    res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
-    if (VK_SUCCESS != res) {
-        delete[] layers;
-        return false;
-    }
-    for (uint32_t i = 0; i < layerCount; ++i) {
-        if (nonPatchVersion <= remove_patch_version(layers[i].specVersion)) {
-            fDeviceLayerStrings->push_back() = layers[i].layerName;
+    SkTArray<const char*> extensionNames;
+    GetExtensionArrayFromFlags(extensionFlags, &extensionNames);
+    for (int i = 0; i < extensionNames.count(); ++i) {
+        // if not already in the list, add it
+        if (find_string(fExtensionStrings, extensionNames[i]) < 0) {
+            fExtensionStrings.push_back() = extensionNames[i];
+            SkTQSort(&fExtensionStrings.front(), &fExtensionStrings.back(), cmp);
         }
     }
-    delete[] layers;
-    if (!fDeviceLayerStrings->empty()) {
-        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
-        SkTQSort(&fDeviceLayerStrings->front(), &fDeviceLayerStrings->back(), cmp);
-    }
-
-    // device extensions
-    // via Vulkan implementation and implicitly enabled layers
-    uint32_t extensionCount = 0;
-    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
-    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
-    if (VK_SUCCESS != res) {
-        delete[] extensions;
-        return false;
-    }
-    for (uint32_t i = 0; i < extensionCount; ++i) {
-        fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
-    }
-    delete[] extensions;
-    if (!fDeviceExtensionStrings->empty()) {
-        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
-        SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
-    }
-    // via explicitly enabled layers
-    layerCount = fDeviceLayerStrings->count();
-    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
-        uint32_t extensionCount = 0;
-        res = EnumerateDeviceExtensionProperties(physDev,
-            (*fDeviceLayerStrings)[layerIndex].c_str(),
-            &extensionCount, nullptr);
-        if (VK_SUCCESS != res) {
-            return false;
-        }
-        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
-        res = EnumerateDeviceExtensionProperties(physDev,
-            (*fDeviceLayerStrings)[layerIndex].c_str(),
-            &extensionCount, extensions);
-        if (VK_SUCCESS != res) {
-            delete[] extensions;
-            return false;
-        }
-        for (uint32_t i = 0; i < extensionCount; ++i) {
-            // if not already in the list, add it
-            if (find_string(*fDeviceExtensionStrings, extensions[i].extensionName) < 0) {
-                fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
-                SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
-            }
-        }
-        delete[] extensions;
-    }
-
-    return true;
 }
 
-bool GrVkExtensions::hasInstanceExtension(const char ext[]) const {
-    return find_string(*fInstanceExtensionStrings, ext) >= 0;
+bool GrVkExtensions::hasExtension(const char ext[]) const {
+    return find_string(fExtensionStrings, ext) >= 0;
 }
 
-bool GrVkExtensions::hasDeviceExtension(const char ext[]) const {
-    return find_string(*fDeviceExtensionStrings, ext) >= 0;
+void GrVkExtensions::GetExtensionArrayFromFlags(uint32_t extensionFlags,
+                                                SkTArray<const char*>* extensions) {
+#ifdef SK_ENABLE_VK_LAYERS
+    if (extensionFlags & kEXT_debug_report_GrVkExtensionFlag) {
+        extensions->push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
+    }
+#endif
+    if (extensionFlags & kKHR_surface_GrVkExtensionFlag) {
+        extensions->push_back(VK_KHR_SURFACE_EXTENSION_NAME);
+    }
+    if (extensionFlags & kKHR_swapchain_GrVkExtensionFlag) {
+        extensions->push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    }
+#ifdef SK_BUILD_FOR_WIN
+    if (extensionFlags & kKHR_win32_surface_GrVkExtensionFlag) {
+        extensions->push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
+    }
+#elif defined(SK_BUILD_FOR_ANDROID)
+    if (extensionFlags & kKHR_android_surface_GrVkExtensionFlag) {
+        extensions->push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
+    }
+#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
+    if (extensionFlags & kKHR_xcb_surface_GrVkExtensionFlag) {
+        extensions->push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
+    }
+#endif
+    // Device extensions
+    if (extensionFlags & kKHR_swapchain_GrVkExtensionFlag) {
+        extensions->push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    }
+    if (extensionFlags & kNV_glsl_shader_GrVkExtensionFlag) {
+        extensions->push_back("VK_NV_glsl_shader");
+    }
 }
 
-bool GrVkExtensions::hasInstanceLayer(const char ext[]) const {
-    return find_string(*fInstanceLayerStrings, ext) >= 0;
-}
-
-bool GrVkExtensions::hasDeviceLayer(const char ext[]) const {
-    return find_string(*fDeviceLayerStrings, ext) >= 0;
-}
-
-void GrVkExtensions::print(const char* sep) const {
-    if (nullptr == sep) {
-        sep = " ";
-    }
-    int cnt = fInstanceExtensionStrings->count();
-    SkDebugf("Instance Extensions: ");
-    for (int i = 0; i < cnt; ++i) {
-        SkDebugf("%s%s", (*fInstanceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
-    }
-    cnt = fDeviceExtensionStrings->count();
-    SkDebugf("\nDevice Extensions: ");
-    for (int i = 0; i < cnt; ++i) {
-        SkDebugf("%s%s", (*fDeviceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
-    }
-    cnt = fInstanceLayerStrings->count();
-    SkDebugf("\nInstance Layers: ");
-    for (int i = 0; i < cnt; ++i) {
-        SkDebugf("%s%s", (*fInstanceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
-    }
-    cnt = fDeviceLayerStrings->count();
-    SkDebugf("\nDevice Layers: ");
-    for (int i = 0; i < cnt; ++i) {
-        SkDebugf("%s%s", (*fDeviceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
-    }
-}
diff --git a/src/gpu/vk/GrVkExtensions.h b/src/gpu/vk/GrVkExtensions.h
deleted file mode 100644
index 8de28f4..0000000
--- a/src/gpu/vk/GrVkExtensions.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrVkExtensions_DEFINED
-#define GrVkExtensions_DEFINED
-
-#include "../private/SkTArray.h"
-#include "SkString.h"
-#include "vk/GrVkDefines.h"
-#include "vk/GrVkInterface.h"
-
-/**
- * This helper queries the Vulkan driver for available extensions and layers, remembers them,
- * and can be queried. It supports queries for both instance and device extensions and layers.
- */
-class SK_API GrVkExtensions {
-public:
-    GrVkExtensions(GrVkInterface::GetProc getProc)
-                     : fGetProc(getProc)
-                     , fInstanceExtensionStrings(new SkTArray<SkString>)
-                     , fDeviceExtensionStrings(new SkTArray<SkString>)
-                     , fInstanceLayerStrings(new SkTArray<SkString>)
-                     , fDeviceLayerStrings(new SkTArray<SkString>) {}
-
-    bool initInstance(uint32_t specVersion);
-    bool initDevice(uint32_t specVersion, VkInstance, VkPhysicalDevice);
-
-    /**
-     * Queries whether an extension or layer is present. Will fail if not initialized.
-     */
-    bool hasInstanceExtension(const char[]) const;
-    bool hasDeviceExtension(const char[]) const;
-    bool hasInstanceLayer(const char[]) const;
-    bool hasDeviceLayer(const char[]) const;
-
-    void print(const char* sep = "\n") const;
-
-private:
-    GrVkInterface::GetProc fGetProc;
-    std::unique_ptr<SkTArray<SkString>>  fInstanceExtensionStrings;
-    std::unique_ptr<SkTArray<SkString>>  fDeviceExtensionStrings;
-    std::unique_ptr<SkTArray<SkString>>  fInstanceLayerStrings;
-    std::unique_ptr<SkTArray<SkString>>  fDeviceLayerStrings;
-};
-
-#endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 65225d9..81787b2 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -36,6 +36,7 @@
 #include "SkMipMap.h"
 #include "SkSLCompiler.h"
 #include "SkTo.h"
+
 #include "vk/GrVkInterface.h"
 #include "vk/GrVkTypes.h"
 
@@ -58,7 +59,7 @@
         return nullptr;
     }
     if (!backendContext.fInterface ||
-        !backendContext.fInterface->validate(backendContext.fExtensions)) {
+        !backendContext.fInterface->validate()) {
         return nullptr;
     }
 
@@ -88,7 +89,7 @@
     fCompiler = new SkSL::Compiler();
 
     fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendContext.fPhysicalDevice,
-                               backendContext.fFeatures, backendContext.fExtensions));
+                               backendContext.fFeatures));
     fCaps.reset(SkRef(fVkCaps.get()));
 
     VK_CALL(GetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &fPhysDevProps));
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 266c916..a8138923 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -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&, const GrVkBackendContext&);
 
     void onResetContext(uint32_t resetBits) override {}
 
diff --git a/src/gpu/vk/GrVkInterface.cpp b/src/gpu/vk/GrVkInterface.cpp
index dedc264..c8f3371 100644
--- a/src/gpu/vk/GrVkInterface.cpp
+++ b/src/gpu/vk/GrVkInterface.cpp
@@ -22,20 +22,27 @@
     };
 }
 
-GrVkInterface::GrVkInterface(const GetInstanceProc& getInstanceProc,
-                             const GetDeviceProc& getDeviceProc,
+GrVkInterface::GrVkInterface(GetProc getProc,
                              VkInstance instance,
                              VkDevice device,
                              uint32_t extensionFlags)
-        : GrVkInterface(make_unified_getter(getInstanceProc, getDeviceProc),
-                        instance,
-                        device,
-                        extensionFlags) {}
+        : fExtensions(extensionFlags) {
+    this->init(getProc, instance, device);
+}
 
 GrVkInterface::GrVkInterface(GetProc getProc,
                              VkInstance instance,
                              VkDevice device,
-                             uint32_t extensionFlags) {
+                             uint32_t instanceExtensionCount,
+                             const char* const* instanceExtensions,
+                             uint32_t deviceExtensionCount,
+                             const char* const* deviceExtensions)
+        : fExtensions(instanceExtensionCount, instanceExtensions, deviceExtensionCount,
+                      deviceExtensions) {
+    this->init(getProc, instance, device);
+}
+
+void GrVkInterface::init(GetProc getProc, VkInstance instance, VkDevice device) {
     if (getProc == nullptr) {
         return;
     }
@@ -59,7 +66,7 @@
     ACQUIRE_PROC(EnumerateDeviceExtensionProperties, instance, VK_NULL_HANDLE);
     ACQUIRE_PROC(EnumerateDeviceLayerProperties, instance, VK_NULL_HANDLE);
 
-    if (extensionFlags & kEXT_debug_report_GrVkExtensionFlag) {
+    if (fExtensions.hasExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
         // Also instance Procs.
         ACQUIRE_PROC(CreateDebugReportCallbackEXT, instance, VK_NULL_HANDLE);
         ACQUIRE_PROC(DebugReportMessageEXT, instance, VK_NULL_HANDLE);
@@ -198,7 +205,7 @@
     if (kIsDebug) { SkDebugf("%s:%d GrVkInterface::validate() failed.\n", __FILE__, __LINE__); } \
     return false;
 
-bool GrVkInterface::validate(uint32_t extensionFlags) const {
+bool GrVkInterface::validate() const {
     // functions that are always required
     if (nullptr == fFunctions.fCreateInstance ||
         nullptr == fFunctions.fDestroyInstance ||
@@ -338,7 +345,7 @@
         RETURN_FALSE_INTERFACE
     }
 
-    if (extensionFlags & kEXT_debug_report_GrVkExtensionFlag) {
+    if (fExtensions.hasExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
         if (nullptr == fFunctions.fCreateDebugReportCallbackEXT ||
             nullptr == fFunctions.fDebugReportMessageEXT ||
             nullptr == fFunctions.fDestroyDebugReportCallbackEXT) {
diff --git a/tools/gpu/vk/VkTestUtils.cpp b/tools/gpu/vk/VkTestUtils.cpp
index e6ddda2..9421b00 100644
--- a/tools/gpu/vk/VkTestUtils.cpp
+++ b/tools/gpu/vk/VkTestUtils.cpp
@@ -59,36 +59,22 @@
     "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);      \
-        if (device != VK_NULL_HANDLE) {                                        \
-            destroy_instance(getProc, inst, debugCallback, hasDebugExtension); \
-        }                                                                      \
-        return false;                                                          \
+static bool should_include_debug_layer(const VkLayerProperties& layerProps) {
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
+        if (!strcmp(layerProps.layerName, kDebugLayerNames[i])) {
+            return true;
+        }
     }
-
-#ifdef SK_ENABLE_VK_LAYERS
+    return false;
+}
 VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
     VkDebugReportFlagsEXT       flags,
     VkDebugReportObjectTypeEXT  objectType,
@@ -112,6 +98,202 @@
 }
 #endif
 
+#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, device)
+
+#ifdef SK_ENABLE_VK_LAYERS
+static uint32_t remove_patch_version(uint32_t specVersion) {
+    return (specVersion >> 12) << 12;
+}
+#endif
+
+static bool init_instance_extensions_and_layers(GrVkInterface::GetProc getProc,
+                                                uint32_t specVersion,
+                                                SkTArray<VkExtensionProperties>* instanceExtensions,
+                                                SkTArray<VkLayerProperties>* instanceLayers) {
+    if (getProc == nullptr) {
+        return false;
+    }
+
+    GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
+
+    if (!EnumerateInstanceExtensionProperties ||
+        !EnumerateInstanceLayerProperties) {
+        return false;
+    }
+
+    VkResult res;
+    uint32_t layerCount = 0;
+#ifdef SK_ENABLE_VK_LAYERS
+    // instance layers
+    res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkLayerProperties* layers = new VkLayerProperties[layerCount];
+    res = EnumerateInstanceLayerProperties(&layerCount, layers);
+    if (VK_SUCCESS != res) {
+        delete[] layers;
+        return false;
+    }
+
+    uint32_t nonPatchVersion = remove_patch_version(specVersion);
+    for (uint32_t i = 0; i < layerCount; ++i) {
+        if (nonPatchVersion <= remove_patch_version(layers[i].specVersion) &&
+            should_include_debug_layer(layers[i])) {
+            instanceLayers->push_back() = layers[i];
+        }
+    }
+    delete[] layers;
+#endif
+
+    // instance extensions
+    // via Vulkan implementation and implicitly enabled layers
+    uint32_t extensionCount = 0;
+    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
+    if (VK_SUCCESS != res) {
+        delete[] extensions;
+        return false;
+    }
+    for (uint32_t i = 0; i < extensionCount; ++i) {
+        instanceExtensions->push_back() = extensions[i];
+    }
+    delete [] extensions;
+
+    // via explicitly enabled layers
+    layerCount = instanceLayers->count();
+    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
+        uint32_t extensionCount = 0;
+        res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
+                                                   &extensionCount, nullptr);
+        if (VK_SUCCESS != res) {
+            return false;
+        }
+        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+        res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
+                                                   &extensionCount, extensions);
+        if (VK_SUCCESS != res) {
+            delete[] extensions;
+            return false;
+        }
+        for (uint32_t i = 0; i < extensionCount; ++i) {
+            instanceExtensions->push_back() = extensions[i];
+        }
+        delete[] extensions;
+    }
+
+    return true;
+}
+
+static bool init_device_extensions_and_layers(GrVkInterface::GetProc getProc, uint32_t specVersion,
+                                              VkInstance inst, VkPhysicalDevice physDev,
+                                              SkTArray<VkExtensionProperties>* deviceExtensions,
+                                              SkTArray<VkLayerProperties>* deviceLayers) {
+    if (getProc == nullptr) {
+        return false;
+    }
+
+    GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
+    GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
+
+    if (!EnumerateDeviceExtensionProperties ||
+        !EnumerateDeviceLayerProperties) {
+        return false;
+    }
+
+    VkResult res;
+    // device layers
+    uint32_t layerCount = 0;
+#ifdef SK_ENABLE_VK_LAYERS
+    res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkLayerProperties* layers = new VkLayerProperties[layerCount];
+    res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
+    if (VK_SUCCESS != res) {
+        delete[] layers;
+        return false;
+    }
+
+    uint32_t nonPatchVersion = remove_patch_version(specVersion);
+    for (uint32_t i = 0; i < layerCount; ++i) {
+        if (nonPatchVersion <= remove_patch_version(layers[i].specVersion) &&
+            should_include_debug_layer(layers[i])) {
+            deviceLayers->push_back() = layers[i];
+        }
+    }
+    delete[] layers;
+#endif
+
+    // device extensions
+    // via Vulkan implementation and implicitly enabled layers
+    uint32_t extensionCount = 0;
+    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
+    if (VK_SUCCESS != res) {
+        delete[] extensions;
+        return false;
+    }
+    for (uint32_t i = 0; i < extensionCount; ++i) {
+        deviceExtensions->push_back() = extensions[i];
+    }
+    delete[] extensions;
+
+    // via explicitly enabled layers
+    layerCount = deviceLayers->count();
+    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
+        uint32_t extensionCount = 0;
+        res = EnumerateDeviceExtensionProperties(physDev,
+            (*deviceLayers)[layerIndex].layerName,
+            &extensionCount, nullptr);
+        if (VK_SUCCESS != res) {
+            return false;
+        }
+        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+        res = EnumerateDeviceExtensionProperties(physDev,
+            (*deviceLayers)[layerIndex].layerName,
+            &extensionCount, extensions);
+        if (VK_SUCCESS != res) {
+            delete[] extensions;
+            return false;
+        }
+        for (uint32_t i = 0; i < extensionCount; ++i) {
+            deviceExtensions->push_back() = extensions[i];
+        }
+        delete[] extensions;
+    }
+
+    return true;
+}
+
+// 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);      \
+        if (device != VK_NULL_HANDLE) {                                        \
+            destroy_instance(getProc, inst, debugCallback, hasDebugExtension); \
+        }                                                                      \
+        return false;                                                          \
+    }
+
 #define ACQUIRE_VK_PROC_LOCAL(name, instance, device)                          \
     PFN_vk##name grVk##name =                                                  \
         reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
@@ -161,50 +343,25 @@
         kGrVkMinimumVersion,                // apiVersion
     };
 
-    GrVkExtensions extensions(getProc);
-    extensions.initInstance(kGrVkMinimumVersion);
+    SkTArray<VkLayerProperties> instanceLayers;
+    SkTArray<VkExtensionProperties> instanceExtensions;
+
+    if (!init_instance_extensions_and_layers(getProc, kGrVkMinimumVersion,
+                                             &instanceExtensions,
+                                             &instanceLayers)) {
+        return false;
+    }
 
     SkTArray<const char*> instanceLayerNames;
     SkTArray<const char*> instanceExtensionNames;
-    uint32_t extensionFlags = 0;
-    bool hasDebugExtension = false;
-#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]);
+    for (int i = 0; i < instanceLayers.count(); ++i) {
+        instanceLayerNames.push_back(instanceLayers[i].layerName);
+    }
+    for (int i = 0; i < instanceExtensions.count(); ++i) {
+        if (strncmp(instanceExtensions[i].extensionName, "VK_KHX", 6)) {
+            instanceExtensionNames.push_back(instanceExtensions[i].extensionName);
         }
     }
-    if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
-        instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
-        extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
-        hasDebugExtension = true;
-    }
-#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
@@ -217,6 +374,8 @@
         instanceExtensionNames.begin(),            // ppEnabledExtensionNames
     };
 
+    bool hasDebugExtension = false;
+
     ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
     err = grVkCreateInstance(&instance_create, nullptr, &inst);
     if (err < 0) {
@@ -250,7 +409,6 @@
     }
 #endif
 
-    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);
@@ -332,17 +490,29 @@
         presentQueueIndex = graphicsQueueIndex;
     }
 
-    extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
+    SkTArray<VkLayerProperties> deviceLayers;
+    SkTArray<VkExtensionProperties> deviceExtensions;
+    if (!init_device_extensions_and_layers(getProc, kGrVkMinimumVersion,
+                                           inst, physDev,
+                                           &deviceExtensions,
+                                           &deviceLayers)) {
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
 
     SkTArray<const char*> deviceLayerNames;
     SkTArray<const char*> deviceExtensionNames;
-    if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
-        deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
-        extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
+    for (int i = 0; i < deviceLayers.count(); ++i) {
+        deviceLayerNames.push_back(deviceLayers[i].layerName);
     }
-    if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
-        deviceExtensionNames.push_back("VK_NV_glsl_shader");
-        extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
+    for (int i = 0; i < deviceExtensions.count(); ++i) {
+        // Don't use experimental extensions since they typically don't work with debug layers and
+        // often are missing dependecy requirements for other extensions. Additionally, these are
+        // often left behind in the driver even after they've been promoted to real extensions.
+        if (strncmp(deviceExtensions[i].extensionName, "VK_KHX", 6) &&
+            strncmp(deviceExtensions[i].extensionName, "VK_NVX", 6)) {
+            deviceExtensionNames.push_back(deviceExtensions[i].extensionName);
+        }
     }
 
     // query to get the physical device properties
@@ -406,9 +576,13 @@
         return false;
     }
 
-    auto interface =
-        sk_make_sp<GrVkInterface>(getProc, inst, device, extensionFlags);
-    if (!interface->validate(extensionFlags)) {
+    auto interface = sk_make_sp<GrVkInterface>(getProc, inst, device,
+                                               (uint32_t) instanceExtensionNames.count(),
+                                               instanceExtensionNames.begin(),
+                                               (uint32_t) deviceExtensionNames.count(),
+                                               deviceExtensionNames.begin());
+
+    if (!interface->validate()) {
         SkDebugf("Vulkan interface validation failed\n");
         grVkDeviceWaitIdle(device);
         grVkDestroyDevice(device, nullptr);
@@ -425,7 +599,7 @@
     ctx->fQueue = queue;
     ctx->fGraphicsQueueIndex = graphicsQueueIndex;
     ctx->fMinAPIVersion = kGrVkMinimumVersion;
-    ctx->fExtensions = extensionFlags;
+    ctx->fExtensions = 0;
     ctx->fFeatures = featureFlags;
     ctx->fInterface.reset(interface.release());
     ctx->fOwnsInstanceAndDevice = false;
diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp
index 8e0749e..d038c97 100644
--- a/tools/sk_app/VulkanWindowContext.cpp
+++ b/tools/sk_app/VulkanWindowContext.cpp
@@ -12,6 +12,7 @@
 #include "SkSurface.h"
 #include "VulkanWindowContext.h"
 
+#include "vk/GrVkExtensions.h"
 #include "vk/GrVkImage.h"
 #include "vk/GrVkUtil.h"
 #include "vk/GrVkTypes.h"
@@ -56,8 +57,8 @@
         return;
     }
 
-    if (!(backendContext.fExtensions & kKHR_surface_GrVkExtensionFlag) ||
-        !(backendContext.fExtensions & kKHR_swapchain_GrVkExtensionFlag)) {
+    if (!backendContext.fInterface->fExtensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME) ||
+        !backendContext.fInterface->fExtensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
         return;
     }