Refactor Vulkan support to support Fuchsia

- Refactor runtime lookup of Vulkan functions
- Support Magma surfaces
- Add build flags to toggle Vulkan support

BUG=skia:

Change-Id: Ic71965c453507882521443006c4155c7481a9a3f
Reviewed-on: https://skia-review.googlesource.com/9342
Commit-Queue: Greg Daniel <egdaniel@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Michael Jurka <mikejurka@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/.gitignore b/.gitignore
index f292111..ec250f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,6 @@
 bin/gn.exe
 bin/clang-format
 bin/clang-format.exe
+
+vulkan-out
+gl-out
\ No newline at end of file
diff --git a/BUILD.gn b/BUILD.gn
index 1801c32..8bbd12a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -37,6 +37,7 @@
   skia_enable_tools = is_skia_dev_build
   skia_enable_vulkan_debug_layers = is_skia_dev_build && is_debug
   skia_vulkan_sdk = getenv("VULKAN_SDK")
+  skia_link_with_vulkan = true
 }
 declare_args() {
   skia_use_dng_sdk = !is_fuchsia && skia_use_libjpeg_turbo && skia_use_zlib
@@ -47,6 +48,11 @@
   } else {
     skia_use_vulkan = skia_vulkan_sdk != ""
   }
+  if (is_win) {
+    skia_vulkan_headers_path = "$skia_vulkan_sdk/Include"
+  } else {
+    skia_vulkan_headers_path = "$skia_vulkan_sdk/include"
+  }
 }
 
 # Our tools require static linking (they use non-exported symbols).
@@ -133,22 +139,26 @@
   libs = []
   lib_dirs = []
   if (skia_use_vulkan) {
+    include_dirs += [ skia_vulkan_headers_path ]
+
     if (skia_vulkan_sdk != "" && !is_android) {
       if (is_win) {
-        include_dirs += [ "$skia_vulkan_sdk/Include/" ]
         lib_dirs += [
           "$skia_vulkan_sdk/Bin",
           "$skia_vulkan_sdk/Lib",
         ]
       } else {
-        include_dirs += [ "$skia_vulkan_sdk/include/" ]
         lib_dirs += [ "$skia_vulkan_sdk/lib/" ]
       }
     }
-    if (is_win) {
-      libs += [ "vulkan-1.lib" ]
-    } else {
-      libs += [ "vulkan" ]
+
+    if (skia_link_with_vulkan) {
+      defines += [ "SK_LINK_WITH_VULKAN" ]
+      if (is_win) {
+        libs += [ "vulkan-1.lib" ]
+      } else {
+        libs += [ "vulkan" ]
+      }
     }
   }
   if (skia_enable_gpu) {
diff --git a/include/gpu/vk/GrVkBackendContext.h b/include/gpu/vk/GrVkBackendContext.h
index 5e51bee..5ae7b31 100644
--- a/include/gpu/vk/GrVkBackendContext.h
+++ b/include/gpu/vk/GrVkBackendContext.h
@@ -11,8 +11,7 @@
 #include "SkRefCnt.h"
 
 #include "vk/GrVkDefines.h"
-
-struct GrVkInterface;
+#include "vk/GrVkInterface.h"
 
 enum GrVkExtensionFlags {
     kEXT_debug_report_GrVkExtensionFlag    = 0x0001,
@@ -51,10 +50,13 @@
                                             uint32_t queueFamilyIndex)>;
 
     // Helper function to create the default Vulkan objects needed by the GrVkGpu object
+    // If getProc is NULL, a default getProc will be constructed if we are statically linking
+    // against Vulkan.
     // If presentQueueIndex is non-NULL, will try to set up presentQueue as part of device
     // creation using the platform-specific canPresent() function.
     static const GrVkBackendContext* Create(uint32_t* presentQueueIndex = nullptr,
-                                            CanPresentFn = CanPresentFn());
+                                            CanPresentFn = CanPresentFn(),
+                                            GrVkInterface::GetProc getProc = nullptr);
 
     ~GrVkBackendContext() override;
 };
diff --git a/include/gpu/vk/GrVkDefines.h b/include/gpu/vk/GrVkDefines.h
index 9caf2d7..ff8f213 100644
--- a/include/gpu/vk/GrVkDefines.h
+++ b/include/gpu/vk/GrVkDefines.h
@@ -10,11 +10,23 @@
 #define GrVkDefines_DEFINED
 
 #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_WIN32)
-#   define VK_USE_PLATFORM_WIN32_KHR
+#   if !defined(VK_USE_PLATFORM_WIN32_KHR)
+#      define VK_USE_PLATFORM_WIN32_KHR
+#   endif
 #elif defined(SK_BUILD_FOR_ANDROID)
-#   define VK_USE_PLATFORM_ANDROID_KHR
+#   if !defined(VK_USE_PLATFORM_ANDROID_KHR)
+#      define VK_USE_PLATFORM_ANDROID_KHR
+#   endif
 #elif defined(SK_BUILD_FOR_UNIX)
-#   define VK_USE_PLATFORM_XCB_KHR
+#   if defined(__Fuchsia__)
+#     if !defined(VK_USE_PLATFORM_MAGMA_KHR)
+#       define VK_USE_PLATFORM_MAGMA_KHR
+#     endif
+#   else
+#     if !defined(VK_USE_PLATFORM_XCB_KHR)
+#        define VK_USE_PLATFORM_XCB_KHR
+#     endif
+#   endif
 #endif
 
 #if defined(Bool) || defined(Status) || defined(True) || defined(False)
diff --git a/include/gpu/vk/GrVkInterface.h b/include/gpu/vk/GrVkInterface.h
index 9dc0333..dca47ff 100644
--- a/include/gpu/vk/GrVkInterface.h
+++ b/include/gpu/vk/GrVkInterface.h
@@ -15,20 +15,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 /**
- * The default interface is returned by GrVkCreateInterface. This function's
- * implementation is platform-specific.
- */
-
-struct GrVkInterface;
-
-/**
- * Creates a GrVkInterface.
- */
-const GrVkInterface* GrVkCreateInterface(VkInstance instance, VkDevice device,
-                                         uint32_t extensionFlags);
-
-
-/**
  * GrContext uses the following interface to make all calls into Vulkan. When a
  * GrContext is created it is given a GrVkInterface. All functions that should be
  * available based on the Vulkan's version must be non-NULL or GrContext creation
@@ -49,7 +35,15 @@
     typedef SkRefCnt INHERITED;
 
 public:
-    GrVkInterface();
+    using GetProc = std::function<PFN_vkVoidFunction(
+        const char*, // function name
+        VkInstance,  // instance or VK_NULL_HANDLE
+        VkDevice     // device or VK_NULL_HANDLE
+        )>;
+    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.
diff --git a/src/gpu/vk/GrVkBackendContext.cpp b/src/gpu/vk/GrVkBackendContext.cpp
index 5a9de04..3b53f83 100644
--- a/src/gpu/vk/GrVkBackendContext.cpp
+++ b/src/gpu/vk/GrVkBackendContext.cpp
@@ -38,9 +38,32 @@
 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) {
+                                                     CanPresentFn canPresent,
+                                                     GrVkInterface::GetProc getProc) {
+#ifdef SK_LINK_WITH_VULKAN
+    if (getProc == nullptr) {
+        getProc = [](const char* proc_name,
+                     VkInstance instance, VkDevice device) {
+            if (device != VK_NULL_HANDLE) {
+                return vkGetDeviceProcAddr(device, proc_name);
+            }
+            return vkGetInstanceProcAddr(instance, proc_name);
+            };
+    }
+#else
+    SkASSERT(getProc != nullptr);
+#endif
+
     VkPhysicalDevice physDev;
     VkDevice device;
     VkInstance inst;
@@ -56,7 +79,7 @@
         kGrVkMinimumVersion,                // apiVersion
     };
 
-    GrVkExtensions extensions;
+    GrVkExtensions extensions(getProc);
     extensions.initInstance(kGrVkMinimumVersion);
 
     SkTArray<const char*> instanceLayerNames;
@@ -92,7 +115,7 @@
         instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
         extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
     }
-#elif defined(SK_BUILD_FOR_UNIX)
+#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;
@@ -110,40 +133,50 @@
         instanceExtensionNames.begin(),            // ppEnabledExtensionNames
     };
 
-    err = vkCreateInstance(&instance_create, nullptr, &inst);
+    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 = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
+    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
     if (err) {
         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
-        vkDestroyInstance(inst, nullptr);
+        grVkDestroyInstance(inst, nullptr);
         return nullptr;
     }
     SkASSERT(gpuCount > 0);
     // Just returning the first physical device instead of getting the whole array.
     // TODO: find best match for our needs
     gpuCount = 1;
-    err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
+    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
     if (err) {
         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
-        vkDestroyInstance(inst, nullptr);
+        grVkDestroyInstance(inst, nullptr);
         return nullptr;
     }
 
     // query to get the initial queue props size
     uint32_t queueCount;
-    vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
+    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
     SkASSERT(queueCount >= 1);
 
     SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
     // now get the actual queue props
     VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
 
-    vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
+    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
 
     // iterate to find the graphics queue
     uint32_t graphicsQueueIndex = queueCount;
@@ -190,7 +223,7 @@
 
     // query to get the physical device properties
     VkPhysicalDeviceFeatures deviceFeatures;
-    vkGetPhysicalDeviceFeatures(physDev, &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;
@@ -242,15 +275,25 @@
         &deviceFeatures                          // ppEnabledFeatures
     };
 
-    err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device);
+    err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
     if (err) {
         SkDebugf("CreateDevice failed: %d\n", err);
-        vkDestroyInstance(inst, nullptr);
+        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;
-    vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
+    grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
 
     GrVkBackendContext* ctx = new GrVkBackendContext();
     ctx->fInstance = inst;
@@ -261,15 +304,19 @@
     ctx->fMinAPIVersion = kGrVkMinimumVersion;
     ctx->fExtensions = extensionFlags;
     ctx->fFeatures = featureFlags;
-    ctx->fInterface.reset(GrVkCreateInterface(inst, device, extensionFlags));
+    ctx->fInterface.reset(interface.release());
 
     return ctx;
 }
 
 GrVkBackendContext::~GrVkBackendContext() {
-    vkDeviceWaitIdle(fDevice);
-    vkDestroyDevice(fDevice, nullptr);
+    if (fInterface == nullptr) {
+        return;
+    }
+
+    fInterface->fFunctions.fDeviceWaitIdle(fDevice);
+    fInterface->fFunctions.fDestroyDevice(fDevice, nullptr);
     fDevice = VK_NULL_HANDLE;
-    vkDestroyInstance(fInstance, nullptr);
+    fInterface->fFunctions.fDestroyInstance(fInstance, nullptr);
     fInstance = VK_NULL_HANDLE;
 }
diff --git a/src/gpu/vk/GrVkExtensions.cpp b/src/gpu/vk/GrVkExtensions.cpp
index 03b4530..17737f1 100644
--- a/src/gpu/vk/GrVkExtensions.cpp
+++ b/src/gpu/vk/GrVkExtensions.cpp
@@ -30,17 +30,21 @@
     return idx;
 }
 
-#define GET_PROC_LOCAL(inst, F) PFN_vk ## F F = (PFN_vk ## F) vkGetInstanceProcAddr(inst, "vk" #F)
+#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(nullptr, EnumerateInstanceExtensionProperties);
-    GET_PROC_LOCAL(nullptr, EnumerateInstanceLayerProperties);
+    GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
 
     SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
 
@@ -126,10 +130,14 @@
 }
 
 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(inst, EnumerateDeviceExtensionProperties);
-    GET_PROC_LOCAL(inst, EnumerateDeviceLayerProperties);
+    GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
+    GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
 
     SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
 
diff --git a/src/gpu/vk/GrVkExtensions.h b/src/gpu/vk/GrVkExtensions.h
index 2decd15..8de28f4 100644
--- a/src/gpu/vk/GrVkExtensions.h
+++ b/src/gpu/vk/GrVkExtensions.h
@@ -11,6 +11,7 @@
 #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,
@@ -18,7 +19,9 @@
  */
 class SK_API GrVkExtensions {
 public:
-    GrVkExtensions() : fInstanceExtensionStrings(new SkTArray<SkString>)
+    GrVkExtensions(GrVkInterface::GetProc getProc)
+                     : fGetProc(getProc)
+                     , fInstanceExtensionStrings(new SkTArray<SkString>)
                      , fDeviceExtensionStrings(new SkTArray<SkString>)
                      , fInstanceLayerStrings(new SkTArray<SkString>)
                      , fDeviceLayerStrings(new SkTArray<SkString>) {}
@@ -37,6 +40,7 @@
     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;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 77816e0..ed64590 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1380,7 +1380,7 @@
         }
     }
 
-    // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src 
+    // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
     // as image usage flags.
     if (src->origin() == dst->origin() &&
         GrBytesPerPixel(src->config()) == GrBytesPerPixel(dst->config())) {
diff --git a/src/gpu/vk/GrVkInterface.cpp b/src/gpu/vk/GrVkInterface.cpp
index 34f12b4..b08f7ba 100644
--- a/src/gpu/vk/GrVkInterface.cpp
+++ b/src/gpu/vk/GrVkInterface.cpp
@@ -9,163 +9,163 @@
 #include "vk/GrVkBackendContext.h"
 #include "vk/GrVkUtil.h"
 
-GrVkInterface::GrVkInterface() {
-}
+#define ACQUIRE_PROC(name, instance, device) fFunctions.f##name = \
+    reinterpret_cast<PFN_vk##name>(getProc("vk"#name, instance, device));
 
-#define GET_PROC_GLOBAL(F) functions->f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(NULL, "vk" #F)
-#define GET_PROC(F) functions->f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
-#define GET_PROC_LOCAL(inst, F) PFN_vk ## F F = (PFN_vk ## F) vkGetInstanceProcAddr(inst, "vk" #F)
-#define GET_DEV_PROC(F) functions->f ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
+GrVkInterface::GrVkInterface(GetProc getProc,
+                             VkInstance instance,
+                             VkDevice device,
+                             uint32_t extensionFlags) {
+    if (getProc == nullptr) {
+        return;
+    }
+    // Global/Loader Procs.
+    ACQUIRE_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    ACQUIRE_PROC(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    ACQUIRE_PROC(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
 
-const GrVkInterface* GrVkCreateInterface(VkInstance instance, VkDevice device,
-                                         uint32_t extensionFlags) {
-
-    GrVkInterface* interface = new GrVkInterface();
-    GrVkInterface::Functions* functions = &interface->fFunctions;
-
-    GET_PROC_GLOBAL(CreateInstance);
-    GET_PROC_GLOBAL(EnumerateInstanceExtensionProperties);
-    GET_PROC_GLOBAL(EnumerateInstanceLayerProperties);
-    GET_PROC(DestroyInstance);
-    GET_PROC(EnumeratePhysicalDevices);
-    GET_PROC(GetPhysicalDeviceFeatures);
-    GET_PROC(GetPhysicalDeviceFormatProperties);
-    GET_PROC(GetPhysicalDeviceImageFormatProperties);
-    GET_PROC(GetPhysicalDeviceProperties);
-    GET_PROC(GetPhysicalDeviceQueueFamilyProperties);
-    GET_PROC(GetPhysicalDeviceMemoryProperties);
-    GET_PROC(CreateDevice);
-    GET_PROC(DestroyDevice);
-    GET_PROC(EnumerateDeviceExtensionProperties);
-    GET_PROC(EnumerateDeviceLayerProperties);
-    GET_DEV_PROC(GetDeviceQueue);
-    GET_DEV_PROC(QueueSubmit);
-    GET_DEV_PROC(QueueWaitIdle);
-    GET_DEV_PROC(DeviceWaitIdle);
-    GET_DEV_PROC(AllocateMemory);
-    GET_DEV_PROC(FreeMemory);
-    GET_DEV_PROC(MapMemory);
-    GET_DEV_PROC(UnmapMemory);
-    GET_DEV_PROC(FlushMappedMemoryRanges);
-    GET_DEV_PROC(InvalidateMappedMemoryRanges);
-    GET_DEV_PROC(GetDeviceMemoryCommitment);
-    GET_DEV_PROC(BindBufferMemory);
-    GET_DEV_PROC(BindImageMemory);
-    GET_DEV_PROC(GetBufferMemoryRequirements);
-    GET_DEV_PROC(GetImageMemoryRequirements);
-    GET_DEV_PROC(GetImageSparseMemoryRequirements);
-    GET_PROC(GetPhysicalDeviceSparseImageFormatProperties);
-    GET_DEV_PROC(QueueBindSparse);
-    GET_DEV_PROC(CreateFence);
-    GET_DEV_PROC(DestroyFence);
-    GET_DEV_PROC(ResetFences);
-    GET_DEV_PROC(GetFenceStatus);
-    GET_DEV_PROC(WaitForFences);
-    GET_DEV_PROC(CreateSemaphore);
-    GET_DEV_PROC(DestroySemaphore);
-    GET_DEV_PROC(CreateEvent);
-    GET_DEV_PROC(DestroyEvent);
-    GET_DEV_PROC(GetEventStatus);
-    GET_DEV_PROC(SetEvent);
-    GET_DEV_PROC(ResetEvent);
-    GET_DEV_PROC(CreateQueryPool);
-    GET_DEV_PROC(DestroyQueryPool);
-    GET_DEV_PROC(GetQueryPoolResults);
-    GET_DEV_PROC(CreateBuffer);
-    GET_DEV_PROC(DestroyBuffer);
-    GET_DEV_PROC(CreateBufferView);
-    GET_DEV_PROC(DestroyBufferView);
-    GET_DEV_PROC(CreateImage);
-    GET_DEV_PROC(DestroyImage);
-    GET_DEV_PROC(GetImageSubresourceLayout);
-    GET_DEV_PROC(CreateImageView);
-    GET_DEV_PROC(DestroyImageView);
-    GET_DEV_PROC(CreateShaderModule);
-    GET_DEV_PROC(DestroyShaderModule);
-    GET_DEV_PROC(CreatePipelineCache);
-    GET_DEV_PROC(DestroyPipelineCache);
-    GET_DEV_PROC(GetPipelineCacheData);
-    GET_DEV_PROC(MergePipelineCaches);
-    GET_DEV_PROC(CreateGraphicsPipelines);
-    GET_DEV_PROC(CreateComputePipelines);
-    GET_DEV_PROC(DestroyPipeline);
-    GET_DEV_PROC(CreatePipelineLayout);
-    GET_DEV_PROC(DestroyPipelineLayout);
-    GET_DEV_PROC(CreateSampler);
-    GET_DEV_PROC(DestroySampler);
-    GET_DEV_PROC(CreateDescriptorSetLayout);
-    GET_DEV_PROC(DestroyDescriptorSetLayout);
-    GET_DEV_PROC(CreateDescriptorPool);
-    GET_DEV_PROC(DestroyDescriptorPool);
-    GET_DEV_PROC(ResetDescriptorPool);
-    GET_DEV_PROC(AllocateDescriptorSets);
-    GET_DEV_PROC(FreeDescriptorSets);
-    GET_DEV_PROC(UpdateDescriptorSets);
-    GET_DEV_PROC(CreateFramebuffer);
-    GET_DEV_PROC(DestroyFramebuffer);
-    GET_DEV_PROC(CreateRenderPass);
-    GET_DEV_PROC(DestroyRenderPass);
-    GET_DEV_PROC(GetRenderAreaGranularity);
-    GET_DEV_PROC(CreateCommandPool);
-    GET_DEV_PROC(DestroyCommandPool);
-    GET_DEV_PROC(ResetCommandPool);
-    GET_DEV_PROC(AllocateCommandBuffers);
-    GET_DEV_PROC(FreeCommandBuffers);
-    GET_DEV_PROC(BeginCommandBuffer);
-    GET_DEV_PROC(EndCommandBuffer);
-    GET_DEV_PROC(ResetCommandBuffer);
-    GET_DEV_PROC(CmdBindPipeline);
-    GET_DEV_PROC(CmdSetViewport);
-    GET_DEV_PROC(CmdSetScissor);
-    GET_DEV_PROC(CmdSetLineWidth);
-    GET_DEV_PROC(CmdSetDepthBias);
-    GET_DEV_PROC(CmdSetBlendConstants);
-    GET_DEV_PROC(CmdSetDepthBounds);
-    GET_DEV_PROC(CmdSetStencilCompareMask);
-    GET_DEV_PROC(CmdSetStencilWriteMask);
-    GET_DEV_PROC(CmdSetStencilReference);
-    GET_DEV_PROC(CmdBindDescriptorSets);
-    GET_DEV_PROC(CmdBindIndexBuffer);
-    GET_DEV_PROC(CmdBindVertexBuffers);
-    GET_DEV_PROC(CmdDraw);
-    GET_DEV_PROC(CmdDrawIndexed);
-    GET_DEV_PROC(CmdDrawIndirect);
-    GET_DEV_PROC(CmdDrawIndexedIndirect);
-    GET_DEV_PROC(CmdDispatch);
-    GET_DEV_PROC(CmdDispatchIndirect);
-    GET_DEV_PROC(CmdCopyBuffer);
-    GET_DEV_PROC(CmdCopyImage);
-    GET_DEV_PROC(CmdBlitImage);
-    GET_DEV_PROC(CmdCopyBufferToImage);
-    GET_DEV_PROC(CmdCopyImageToBuffer);
-    GET_DEV_PROC(CmdUpdateBuffer);
-    GET_DEV_PROC(CmdFillBuffer);
-    GET_DEV_PROC(CmdClearColorImage);
-    GET_DEV_PROC(CmdClearDepthStencilImage);
-    GET_DEV_PROC(CmdClearAttachments);
-    GET_DEV_PROC(CmdResolveImage);
-    GET_DEV_PROC(CmdSetEvent);
-    GET_DEV_PROC(CmdResetEvent);
-    GET_DEV_PROC(CmdWaitEvents);
-    GET_DEV_PROC(CmdPipelineBarrier);
-    GET_DEV_PROC(CmdBeginQuery);
-    GET_DEV_PROC(CmdEndQuery);
-    GET_DEV_PROC(CmdResetQueryPool);
-    GET_DEV_PROC(CmdWriteTimestamp);
-    GET_DEV_PROC(CmdCopyQueryPoolResults);
-    GET_DEV_PROC(CmdPushConstants);
-    GET_DEV_PROC(CmdBeginRenderPass);
-    GET_DEV_PROC(CmdNextSubpass);
-    GET_DEV_PROC(CmdEndRenderPass);
-    GET_DEV_PROC(CmdExecuteCommands);
+    // Instance Procs.
+    ACQUIRE_PROC(EnumeratePhysicalDevices, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceFeatures, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceFormatProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceImageFormatProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceMemoryProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(GetPhysicalDeviceSparseImageFormatProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(DestroyInstance, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(CreateDevice, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(DestroyDevice, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(EnumerateDeviceExtensionProperties, instance, VK_NULL_HANDLE);
+    ACQUIRE_PROC(EnumerateDeviceLayerProperties, instance, VK_NULL_HANDLE);
 
     if (extensionFlags & kEXT_debug_report_GrVkExtensionFlag) {
-        GET_PROC(CreateDebugReportCallbackEXT);
-        GET_PROC(DebugReportMessageEXT);
-        GET_PROC(DestroyDebugReportCallbackEXT);
+        // Also instance Procs.
+        ACQUIRE_PROC(CreateDebugReportCallbackEXT, instance, VK_NULL_HANDLE);
+        ACQUIRE_PROC(DebugReportMessageEXT, instance, VK_NULL_HANDLE);
+        ACQUIRE_PROC(DestroyDebugReportCallbackEXT, instance, VK_NULL_HANDLE);
     }
 
-    return interface;
+    // Device Procs.
+    ACQUIRE_PROC(GetDeviceQueue, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(QueueSubmit, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(QueueWaitIdle, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DeviceWaitIdle, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(AllocateMemory, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(FreeMemory, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(MapMemory, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(UnmapMemory, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(FlushMappedMemoryRanges, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(InvalidateMappedMemoryRanges, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetDeviceMemoryCommitment, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(BindBufferMemory, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(BindImageMemory, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetBufferMemoryRequirements, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetImageMemoryRequirements, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetImageSparseMemoryRequirements, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(QueueBindSparse, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateFence, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyFence, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(ResetFences, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetFenceStatus, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(WaitForFences, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateSemaphore, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroySemaphore, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateEvent, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyEvent, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetEventStatus, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(SetEvent, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(ResetEvent, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateQueryPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyQueryPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetQueryPoolResults, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateBufferView, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyBufferView, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetImageSubresourceLayout, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateImageView, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyImageView, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateShaderModule, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyShaderModule, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreatePipelineCache, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyPipelineCache, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetPipelineCacheData, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(MergePipelineCaches, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateGraphicsPipelines, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateComputePipelines, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyPipeline, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreatePipelineLayout, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyPipelineLayout, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateSampler, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroySampler, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateDescriptorSetLayout, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyDescriptorSetLayout, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateDescriptorPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyDescriptorPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(ResetDescriptorPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(AllocateDescriptorSets, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(FreeDescriptorSets, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(UpdateDescriptorSets, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateFramebuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyFramebuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateRenderPass, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyRenderPass, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(GetRenderAreaGranularity, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CreateCommandPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(DestroyCommandPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(ResetCommandPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(AllocateCommandBuffers, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(FreeCommandBuffers, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(BeginCommandBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(EndCommandBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(ResetCommandBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBindPipeline, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetViewport, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetScissor, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetLineWidth, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetDepthBias, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetBlendConstants, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetDepthBounds, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetStencilCompareMask, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetStencilWriteMask, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetStencilReference, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBindDescriptorSets, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBindIndexBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBindVertexBuffers, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdDraw, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdDrawIndexed, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdDrawIndirect, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdDrawIndexedIndirect, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdDispatch, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdDispatchIndirect, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdCopyBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdCopyImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBlitImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdCopyBufferToImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdCopyImageToBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdUpdateBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdFillBuffer, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdClearColorImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdClearDepthStencilImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdClearAttachments, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdResolveImage, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdSetEvent, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdResetEvent, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdWaitEvents, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdPipelineBarrier, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBeginQuery, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdEndQuery, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdResetQueryPool, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdWriteTimestamp, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdCopyQueryPoolResults, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdPushConstants, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdBeginRenderPass, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdNextSubpass, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdEndRenderPass, VK_NULL_HANDLE, device);
+    ACQUIRE_PROC(CmdExecuteCommands, VK_NULL_HANDLE, device);
 }
 
 #ifdef SK_DEBUG